List:
- 是一个接口,继承自Collection
- List中的元素可以重复,且有序
ArrayList
- 底层数据结构:数组
- 是否有序:是
- 大小是否固定:大小可变,规模动态增加
- 是否线程安全:否
- 是否允许加入null:允许,且可以加入多个null
- 优点:查询快
- 缺点:增加删除慢
- 使用
Collections.sort()
可以对List排序;这个排序是自然排序;想要对自己的类排序,就需要像TreeMap/TreeSet一样重写Comparable接口下的方法
上盘代码:
public static void main(String[] args) {
List<String> l=new ArrayList<>();
ArrayList<String> al=new ArrayList<>();
al.add("1");
l.add("张");
l.add("李");
al.add("5");
al.add("3");
al.set(1, "4");
l.addAll(1, al);
//List转数组
String[] larray=l.toArray(new String[] {});
for (int i = 0; i < larray.length; i++) {
System.out.print(larray[i]+"--");
}
//对List排序
Collections.sort(l);
System.out.println();
System.out.println("al:"+al);
System.out.println("l:"+l);
System.out.println("l的大小:"+l.size());
}
运行结果:
张--1--4--3--李--
al:[1, 4, 3]
l:[1, 3, 4, 张, 李]
l的大小:5
LinkedList
- 底层数据结构:双向链表
- 是否有序:是
- 是否线程安全:否
- 输出:自带迭代器ListIterator
-
- 线程不安全怎么解决:
List list = Collections.synchronizedList(new LinkedList(...));
- 线程不安全怎么解决:
- 优点:
- 当在List中间插入数据时,LinkedList速度比较快
- 删除数据快,以下操作即搞定node.previous.next = node.next;node.next.previous = node.previous;node = null
- 缺点:
- 获取数据慢,需要从Head节点进行查找
- 遍历数据慢,每次获取数据都从头开始。
Vector
- 底层数据结构:数组
- 是否有序:是
- 是否线程安全:是
- 遍历Vector:可以使用iterator或Enumeration。
- 是否允许加入空值:允许,且可以有多个null。
- 优点:查询快
- 缺点:增加删除慢
- 大小:动态增加
关于大小如何动态增加:
Vector有三中构造方法:
public vector()
public vector(int initialcapacity,int capacityIncrement)
public vector(int initialcapacity)
这里使用第一种构造方法时,系统自动对vector进行管理。
如果使用后两种方法,系统将根据参数(initialcapacity:指定了vector的初始容量,capacityIncrement:是扩充因子,为0时表示每次扩充一倍)设定vector的容量,当存放的数据个数超过容量时,系统会扩充vector的存储容量。
加个代码吧:
public static void main(String[] args) {
Vector<Object> vt=new Vector<>();
vt.add(1);
vt.add("张无忌");
vt.add('a');
vt.add("张无忌");
vt.add(null);
System.out.println("Vector的容量:"+vt.capacity());
System.out.println("vt的大小:"+vt.size());
System.out.println("第一个张无忌在List中的位置:"+vt.indexOf("张无忌"));
System.out.println("最后一个张无忌在List中的位置:"+vt.lastIndexOf("张无忌"));
//直接输出List
System.out.println(vt);
//使用Iterator进行输出
System.out.print("使用Iterator进行输出:");
Iterator<Object> iter=vt.iterator();
while(iter.hasNext()) {
System.out.print(iter.next()+",");
}
//使用Enumeration进行输出
System.out.print("\n使用Enumeration进行输出:");
Enumeration<Object> en=vt.elements();
while(en.hasMoreElements()) {
System.out.print(en.nextElement()+",");
}
}
运行结果:
Vector的容量:10
vt的大小:5
第一个张无忌在List中的位置:1
最后一个张无忌在List中的位置:3
[1, 张无忌, a, 张无忌, null]
使用Iterator进行输出:1,张无忌,a,张无忌,null,
使用Enumeration进行输出:1,张无忌,a,张无忌,null,
Vector和ArrayList的区别:
- 最大的区别:Vector是线程安全,而ArrayList不是
- Vector对象一但创建就会初始化一个容量为10的数组,而ArrayList是初始化一个容量为0的数组,添加第一个元素时才会扩充容量为10。且默认情况下,Vector是2倍扩充,而ArrayList是1.5被扩充。
- remove()、clear()、set()、get()、lastIndexof()、contains()、size()、isEmpty()都是synchronized修饰的。
vector和arrayList的相同之处: - 都实现了List接口
- 底层数据结构都是数组
- API的实现几乎相同
- 扩容机制一样:即创建一个新的所需容量大小的数组,把旧数组中的所有元素拷贝到新数组中。这就是扩容机制
- 查询、修改比较快,但增加删除比较慢
附加在结尾的PS
在使用List时,因为List是接口,无法直接实例化,但是我们可以通过
List<String> list=new ArrayList<>();
来间接获得一个实例化的list,这里的list只能调用List中的函数,对于ArrayList中特有的函数,list无法调用。
这样做的好处是,当我们不需要list调用ArrayList方法,而是调用LinkedList中的方法时,我们只需要更改成List<String> list=new LinkedList<>();
而不需要改动其他代码。这提高了代码的可维护性,可复用性,可扩展性以及灵活性。
当List与ArrayList中有同名的方法f()
时,使用list.f()
调用的是ArrayList中的f()
方法。
当List与ArrayList中有相同的成员时,如在List中static int id=1,在ArrayList中static int id=2;调用System.out.println(list.id);
的结果是List中id的值即为1
代码为证:
public class Demo {
public static void main(String[] args) {
Animal test = new Cat();
test.run();
System.out.println(test.id);
}
}
abstract class Animal {
static int id = 1;
public void shout() {
System.out.println("Animal shout...");
}
public void run() {
System.out.println("Ainmal run...");
}
}
class Cat extends Animal {
static int id = 2;
String name;
public void eat() {
System.out.println("cat eat...");
}
@Override
public void shout() {
System.out.println("cat shout...");
}
@Override
public void run() {
System.out.println("cat run...");
}
}
运行结果:
cat run...
1