目录
List
在我前面的一篇文章中涉及到了一张图片,这个图片涉及的内容是集合的框架,在那张图片上,相信大家也能看到List的存在。那么我们再这来简单介绍一下。
- 根据这个图片,我们可以看出,List是一个接口,继承了Collection接口,Collection又继承了Iterable接口。
- Collection接口中规范了后面容器中的一些常用方法。下面为一些常见的方法。
- Iterable接口中,也设计了一些方法,继承这个接口的都可以实现逐个元素依次遍历。
- 站在数据结构角度来看,List接口就是一个线性表。线性表的定义为n个具有相同类型元素的有限序列,在该序列上可以进行增删改查等操作。
- 虽然List接口可以表示线性表,但毕竟他是个接口,并不能实例化,但他提供了很多方法,常用的如下:
- 如果想使用List,我们必须创建类实现这个接口,比方说我们即将讲述的ArrayList和LinkedList均实现了这个接口。
认识线性表,顺序表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构.
常见的线性表:顺序表、链表、栈、队列线性表逻辑结构是线性的,可以看成一条直线,但物理结构不一定连续。通常情况下用数组存储的时候,地址为连续的。一般采用链式存储的时候,地址为不连续的。
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
ArrayList
ArrayList实现了很多接口,有了很多特性:
1.实现了RandomAccess接口,表明支持随机访问。
2.实现了Cloneable接口,表明可以进行克隆。
3.实现了Serializable接口,表明可以序列化。
4.ArrayList实现了List接口。并且ArrayList底层是一段连续空间,并且可以动态扩容,是一个动态类型顺序表。
ArrayList的构造
构造ArrayList有三种方法:无参构造;通过其他集合进行构造;通过指定顺序表初始容量去构造。
java
//无参构造
List<Integer> list1 = new ArrayList<>();
//传递一个初始容量
List<Integer> list2 = new ArrayList<>(10);
//传递一个集合构造(这样构造出来的和传递的集合的元素一摸一样)
List<Integer> list3 = new ArrayList<>(list1);
这里可能会有人产生疑问,为什么我们构造ArrayList的时候采用的动态绑定的方式(向上转型)而不是直接对ArrayList进行实例化。
简单来说,就是为了方便,List实现了很多接口,当我们有一天不想用ArrayList的时候,我们只需要把后半部分换成我们需要的,其余全都不用动。(如果有人还是不懂向上转型,可以去看看我的博客哟!多态)
ArrayList的常用方法
这里就给大家介绍一下常用的方法,当大家遇到的方法没见过,可以去帮助手册查查。
- 除了上表中的还有一个方法很常用,就是size()这个方法用来获取list的长度。
ArrayList的遍历
遍历有三种方式:普通for循环,foreach,迭代器。
java
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
for (int i = 0; i < list.size(); i++) {
//获取某个下标的元素,用get方法
System.out.print(list.get(i) + "\t");
}
System.out.println();
//2.foreach遍历(这里我们用Integer接收,因为我们上面泛型就是Integer)
for (Integer i : list) {
System.out.print(i + "\t");
}
System.out.println();
//3.迭代器遍历
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
这里我就想说一点,大家是否还记得在这篇文章开始就说collection实现了iterable接口。所以实现这个接口的目的就是可以使用迭代器逐个遍历。
ArrayList的扩容
在学习完后ArrayList的三种构造后,大家有没有一个疑问呢?对于无参构造时,他的大小究竟多大呢?我没有指定大小呀,他为啥可以盛放呢?
我们就需要去看源码,了解代码怎么编写的,进一步知道怎么分配空间的。
这里我就不带大家分析源码了,但希望大家记住下面这些东西哦!
- 当我们编写了Listlist = new ArrayList<>();时,并没有分配内存空间,只有我们第一次调用了add时才会分配内存空间。
- 当我们第一次调用add时,会分配10个连续空间。
- 当分配的空间满了后,会自动扩容,正常会按照1.5倍大小进行扩容。
- 在真正扩容前会先检测一下是否真的要扩容,是就调用相关方法进行扩容,使用copyOf进行扩容。