集合:
java集合是使程序能够存储和操纵元素不固定的一组数据。所有java集合类都位于java.util包中
数组和集合的区别:
数组:长度固定,存放任意同一种类型
集合:长度不固定,只能存放引用类型(如果集合中存放基本类型,要将其“装箱”成对应的基本类型包装类)
collection 是集合的父类,collection中的方法是集合中每个子类都有的
Collection c1 = new ArrayList();创建集合
System.out.println(c1.isEmpty());判断是否为空
c1.add(1);基本类型先进行自动装箱,然后再向上转型
c1.add("xxxxx");
c1.remove("xxxxx");删除
c1.clear();清空集合
迭代器:可以屏蔽底层数据存储的差异性
生成迭代器:Iterator it = c.iterator();
迭代器一旦创建,集合中元素不能删除和添加,否则就需要重新生成迭代器
如果在使用迭代器的过程中,需要进行删除,必须使用迭代器的remove方法
迭代器遍历完之后,想再次遍历 只能重新生成
boolean contains(Object o) : 判断是否包含某个元素
boolean remove(Object o) : 删除指定元素
这两个方法,底层都会调用equals方法进行比较
如果存储的是自定义的类型,使用contains和remove 需要覆写equals方法
List:有序可重复,存入顺序和取出顺序是一致的
ArrayList:底层是数组,查询和更改效率极高,添加和删除效率较低
LinkedList:底层是双向链表,查询效率较低,添加删除效率较高
Vector:已经过时了,底层也是数组,ArrayList是Vector的升级版
Vector 默认容量是10,扩大容量是2倍,线程安全,效率较低
ArrayList默认容量是10,扩大容量是1.5倍,非线程安全,效率较高
ArrayList list = new ArrayList();
ArrayList底层是Object[]数组,这就意味着只能保存引用类型
但由于基本类型会自动装箱为包装类类型,所以Object[]数组什么都能放
add(E e);将元素添加到列表尾部
add(int index, E e);将元素添加到指定位置
Arraylist覆写了toString方法,所以打印结果不是内存地址,而是里边的数据
list.set(0, 96);替换指定位置上的元素
list.get(i);根据索引获取对应的元素
list.remove(int index);根据索引删除元素
remove(Object object)删除指定元素
要把数据封装到Integer类型中,不然就代表的是下标
遍历方法:
迭代器
Iterator it =list.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
forEach
for (Object object : list) {
System.out.print(object+" ");
}
for 循环
for (int i = 0; i <list.size(); i++) {
System.out.print(list.get(i)+" ");
}
LinkedList:底层是双向链表
链表的节点由三个部分构成:
1、添加的元素
2、下一个节点的引用
3、上一个节点的引用
链表数据结构,在内存中存储也不是连续的,所以没有固定下标,因此查询效率低
因为内存空间不是连续的,只是能找到下一个节点,因此添加和删除就变得容易了
LinkedList linkedList = new LinkedList();
linkedList.add(99);尾部添加,成功返回true
linkedList.push(98);头部添加
linkedList.addLast(100);尾部添加
linkedList.addFirst(97);头部添加
linkedList.offerLast(101);尾部添加
linkedList.offerFirst(96);头部添加
没什么区别,本质都是调用linkLast和linkFirst,主要解决命名习惯问题
System.out.print(linkedList.getLast());获取最后一个数据
System.out.print(linkedList.getFirst());获取第一个数据
System.out.println(linkedList.get(2));
根据下标获取,这个下标决定的是循环的次数,模拟出来下标获取数据
链表没有下标
linkedList.set(4, 95);设置对应下标的数据
linkedList.remove(1);根据索引删除元素
linkedList.remove(new Integer(98));删除指定元素
linkedList.poll();获取第一个元素并删除
linkedList.pop();获取第一个元素并删除
创建ArrayList对象的时候,长度为0,可以参考ArrayList的无参构造
第一次添加元素的时候,长度设置为10,每次扩容是原来的1.5倍
实现方式:长度+长度>>1
使用ArrayList和LinkedList 分别初始化 1000W条数据
并随机查询 和删除 测试效率问题
ArrayList初始化完成 : 10000000 条数据耗时 2653
LinkedList初始化完成 : 10000000 条数据耗时 7710
ArrayList查询 6416497 对应的值为 6416497
ArrayList查询完成 : 6416497 条数据耗时 0
LinkeList查询 6416497 对应的值为 6416497
LinkeList查询完成 : 6416497 条数据耗时 14
ArrayList删除完成 : 100000 条数据耗时 219
LinkedList删除完成 : 100000 条数据耗时 1717
数据分析 : 查询一定是数组快,但是结果有时候显示添加和删除也是数组快
因为数组的自动扩容机制,1.5倍增长,导致添加大量数据,才需要创建一个数组对象进行扩容,
而删除元素后,容量并没有更改变小
链表每次添加都需要创建新的节点对象,而删除也是需要重新指向节点引用
总结 :
插入位置的选取对LinkedList影响非常大,一直向后面添加,ArrayList会比LinkedList快,因为ArrayList有自动扩容
对于LinkedList是添加,但是对于ArrayList来说,只是向已有空间中赋值,相当于是更改操作,而数组查询和更改效率是比较高的
链表进行添加删除的时候,只需要引用指向即可,而数组需要数据移动位置,所以如果向前边添加数据,则链表快很多