长度区别 | 内容区别 | 元素内容 | 对应增删改查的方法 | |
数组 | 固定长度,无法自动扩容 | 基本类型或引用类型 | 只能存储同一种类型 | 没有 |
集合 | 可变 | 只有引用类型 | 可以存储不同类型 | 有 |
扩展:什么是引用类型?
Java中有四种引用类型:强引用、软引用、弱引用、虚引用。
强引用:Object o = new Object();
什么是集合?
-
集合只能存放对象 存放基本数据类型的包装类
-
集合是可变长度,不限制元素的类型,存储任意类类型的数据,也可以限定元素类型(泛型)
-
集合可以自动扩容
-
集合类支持泛型
集合的类结构图
集合两大体系 :Collection、Map
Collection接口
存储的单一对象
List接口
可重复,有序(有下标)
实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。
Set接口
唯一,无序(没有下标)
实现了Set接口的集合有:EnumSet、HashSet、TreeSet。
Map接口:
存储的key/value键值对
key 任意数据类型,value 任意数据类型。
key:唯一 ,value: 可重复。
实现map的有:HashMap、TreeMap、HashTable、Properties、EnumMap。
另外还有三个分支,均是为上述两大家族服务的。
1、 Iterator(迭代器)家族。主要用于遍历Colleciton接口的及其子类而设计。
2、 Compaator(比较器), 在集合中存储对象时候,用于对象之间的比较
3、 Collecitons是工具类。注意该类名带个s,一般就表示工具类。里面提供了N多静态方法,来对Colleciton集合进行操作。
集合类位于java.util包
List
Collection的集合方法
remove() removeAll() 、addAll() 、add()、 clean()
size() contains() isEmpty()
List接口,可重复,有序
多了一组关于下标相关的方法
add(int index,元素)
remove(int index)
set(int index,元素)
int indexOf(元素)
Object get(int 下标)
List常用的实现类
ArrayList:底层以数组结构存放元素 初始容量为十
LinkedList:底层以双向链表结构存放元素
ArrayList
初始容量:10
随着容器中的元素不断增加,容器的大小也会随着增加。在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作。
Object[] elementData; //ArrayList元素存在elementData数组
int size; 元素个数
>>
右移 有符号 oldCapacity /2的(n-m)次方 正数高位补0 负数高位补1
>>>
无符号右移 高位补0
<<
左移 低位补0copyOf(旧数组,新长度)
每次扩容是1.5倍 grow
对象比较
== equals() 都是在比较地址码是否一样
equals() 从object继承
在实际开发中: 两个对象是否是同一个对象: 1. 如果地址码是否一样, 2. 两个对象的属性值是否一样
对自定义的类类型,重写Object方法、hashCode() 哈希算法
Set集合判断一个对象是否相等
判断两个hashCode是否一样,如果一样,进行equlas()
如果equals()返回true,表示为同一个对象
如果equals()返回true,表示不是同一个对象
如果hashCode不一样,不会判断equals(),不是同一个对象
List判断两个对象是否相等
运用重写的equals(),与hashCode无关
对象比较
== equals() 都是在比较地址码是否一样
equals() 从object继承
在实际开发中: 两个对象是否是同一个对象: 1. 如果地址码是否一样, 2. 两个对象的属性值是否一样
对自定义的类类型,重写Object方法、hashCode() 哈希算法
Set集合判断一个对象是否相等
判断两个hashCode是否一样,如果一样,进行equlas()
如果equals()返回true,表示为同一个对象
如果equals()返回true,表示不是同一个对象
如果hashCode不一样,不会判断equals(),不是同一个对象
List判断两个对象是否相等
运用重写的equals(),与hashCode无关
LinkedList 双向链表
ArrayList:
数组结构, 查询效率高, 修改(插入元素,删除元素)效率低
LinkedList:
双向链表结构: 查询效率低, 修改效率高
它除了有ArrayList的基本操作方法外还额外提供了get,remove,insert方法在LinkedList的首部或尾部。
LinkedList不能随机访问,它所有的操作都是要按照双重链表的需要执行。在列表中索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。
Vector
与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。
Set集合
唯一,无序(没有次序,没有下标)
场景:去重
常见实现类:HashSet、TreeSet(可排序)、LinkedHashSet (有次序)
HashSet
对于自定义对象而言,要重写 hashCode() 和 equals() 这两个方法。
实现原理:借助HashMap,HashSet存放的元素作为HashMap的key,
HashSet判断这个是否是已存在:
HashSet判断两个对象的HashCode码是否一样,如果不一样,set集合认为这两个对象不是同一个对象
如果HashCode码一样,判断eqauls是否为true,如果为false,也不是同一个对象
HashCode一样,eqauls()是true,表示同一个对象
去重
去重的基本原理是:
先计算对象的哈希值,如果哈希值所对应的位置上没有 元素,
直接,存入集合当中,无需调用equals()方法,
如果有,调用equals()比较两个对象的内容是否相同,
如果相同,就舍弃,如果不同,就存入。
方法:
- for循环if判断
set集合无法通过for循环遍历 没有下标,没有get方法
只能通过迭代器遍历
利用set去重
List list = new ArrayList(); Set set = new HashSet(list); List list = new ArrayList(set);
怎么把同一个对象在HashSet添加两次?
不重写构造方法 new新的对象
迭代器
jdk迭代器用于遍历Collection接口的集合(set、List)
java.util.Iterator 接口 只能向下遍历 next()
子接口 ListIterator 只能遍历List集合 可以向下、向上遍历 add hasNext() hasPrevious() ...
得到集合迭代器对象:
集合的
boolean hasNext() 判断是否有下一个元素
Iterator iter = set.iteraor();//通过迭代器
//循环获取
while(iter.hasNext()){
//获取元素
Object ele = iter.next();
}
jdk对迭代器的简化,forEach循环,增强for循环
Iterator iter = set.iteraor();//通过迭代器
//循环获取
while(iter.hasNext()){
//获取元素
Object ele = iter.next();
}
使用迭代器遍历集合,删除、增加元素 都会产生 并发修改异常
java.util.ConcurrentModificationException
modcount != expectCount避免多线程并发修改集合
modCount 记录修改次数
得到迭代器对象时,已经记录迭代器修改记录
避免出现异常,调用迭代器的remove()方法
TreeSet
二叉树: 一个节点最多两个子节点
二叉查找树:左子节点<根节点<右子节点
黑红二叉树 通过变色,左旋,右旋
TreeSet 唯一,可排序(维护一个排序)
CompareTo()
要求这个元素实现Comparable接口
==
相等
>0
大于
<0
小于compareTo方法实现规则:
返回0 this == obj 不会添加新对象
返回正数 this > obj 添加到原来对象的右边
返回负数 this < obj 添加到原来对象的左边
自然排序:要求这个元素实现Comparable接口 重写compareTo() 排序方式固定,不灵活
指定排序:需要元素所在的类实现这个comparator() 接口,指定排序规则,指定排序
如果一个元素既没有实现Comparable接口, 并且程序员创建TreeSet对象时,没有传递Comparator对象, TreeSet添加这个元素的时候,抛出异常 ClassCastException
this(新添加的元素) obj(旧元素)
升序 this - stu 小的在左, 大的在右 >0返回正数: 新的在旧的右边 <0返回负数: 新的在旧的左边 降序 stu - this 大的在左, 小的在右 返回正数,表示 this< obj 添加到原来对象(obj)的右边 返回负数,表示 this > obj // 添加到原来对象obj的左边 分析:this-stu >0 this大 升序 小的在左 大的在右 顺序 :stu-》this
stu-this >0 stu大 降序 大的在左,小的在右 顺序:stu-》this
对集合的选择
对List的选择
1、对于随机查询与迭代遍历操作,数组比所有的容器都要快。所以在随机访问中一般使用ArrayList
2、LinkedList使用双向链表对元素的增加和删除提供了非常好的支持,而ArrayList执行增加和删除元素需要进行元素位移。
3、对于Vector而已,我们一般都是避免使用。
4、将ArrayList当做首选,毕竟对于集合元素而已我们都是进行遍历,只有当程序的性能因为List的频繁插入和删除而降低时,再考虑LinkedList。
对Set的选择
1、HashSet由于使用HashCode实现,所以在某种程度上来说它的性能永远比TreeSet要好,尤其是进行增加和查找操作。
3、虽然TreeSet没有HashSet性能好,但是由于它可以维持元素的排序,所以它还是存在用武之地的。
对Map的选择
1、HashMap与HashSet同样,支持快速查询。虽然HashTable速度的速度也不慢,但是在HashMap面前还是稍微慢了些,所以HashMap在查询方面可以取代HashTable。
2、由于TreeMap需要维持内部元素的顺序,所以它通常要比HashMap和HashTable慢。