Java 集合可分为 Collection 和 Map 两大体系:
单列数据集合
。
双列数据集合
。(类似于高中的函数、映射。(x1,y1),(x2,y2) —> y = f(x) )
所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
Iterator接口的常用方法如下:
public E next()
:返回迭代的下一个元素。public boolean hasNext()
:如果仍有元素可以迭代,则返回 true。 public void test01(){
Collection coll = new ArrayList();
coll.add("小李广");
coll.add("扫地僧");
coll.add("石破天");
Iterator iterator = coll.iterator();
System.out.println(iterator.next());
System.out.println(iterator.next());
System.out.println(iterator.next());
System.out.println(iterator.next()); //报NoSuchElementException异常
}
java.util.List
替代数组。元素有序
、且可重复
,集合中的每个元素都有其对应的顺序索引。ArrayList
、LinkedList
和Vector
。List除了从Collection集合继承的方法外,List 集合里添加了一些根据索引
来操作集合元素的方法。
void add(int index, Object ele)
:在index位置插入ele元素Object get(int index)
:获取指定index位置的元素Object remove(int index)
:移除指定index位置的元素,并返回此元素
Object set(int index, Object ele)
:设置指定index位置的元素为ele
ArrayList 是 List 接口的主要实现类
本质上,ArrayList是对象引用的一个”变长”数组
Arrays.asList(…) 方法返回的 List 集合,既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合
对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高。这是由底层采用链表(双向链表)结构存储数据决定的。
特有方法:
古老
的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全
的。ArrayList作为默认选择
。当插入、删除频繁时,使用LinkedList;Vector总是比ArrayList慢,所以尽量避免使用。HashSet 是 Set 接口的主要实现类,大多数时候使用 Set 集合时都使用这个实现类。
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存储、查找、删除性能。
HashSet 具有以下特点
:
HashSet 集合判断两个元素相等的标准
:两个对象通过 hashCode()
方法得到的哈希值相等,并且两个对象的 equals()
方法返回值为true。
对于存放在Set容器中的对象,对应的类一定要重写hashCode()和equals(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。
HashSet集合中元素的无序性,不等同于随机性。这里的无序性与元素的添加位置有关。具体来说:我们在添加每一个元素到数组中时,具体的存储位置是由元素的hashCode()调用后返回的hash值决定的。导致在数组中每个元素不是依次紧密存放的,表现出一定的无序性。
第1步:当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法得到该对象的 hashCode值,然后根据 hashCode值,通过某个散列函数决定该对象在 HashSet 底层数组中的存储位置。
第2步:如果要在数组中存储的位置上没有元素,则直接添加成功。
第3步:如果要在数组中存储的位置上有元素,则继续比较:
第2步添加成功,元素会保存在底层数组中。
第3步两种添加成功的操作,由于该底层数组的位置已经有元素了,则会通过
链表
的方式继续链接,存储。
注意:如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。
重写equals方法的时候一般都需要同时复写hashCode方法。通常参与计算hashCode的对象的属性也应该参与到equals()中进行计算。
推荐:开发中直接调用Eclipse/IDEA里的快捷键自动重写equals()和hashCode()方法即可。
为什么用Eclipse/IDEA复写hashCode方法,有31这个数字?
首先,选择系数的时候要选择尽量大的系数。因为如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。(减少冲突)
其次,31只占用5bits,相乘造成数据溢出的概率较小。
再次,31可以 由i*31== (i<<5)-1来表示,现在很多虚拟机里面都有做相关优化。(提高算法效率)
最后,31是一个素数,素数作用就是如果我用一个数字来乘以这个素数,那么最终出来的结果只能被素数本身和被乘数还有1来整除!(减少冲突)
LinkedHashSet 是 HashSet 的子类,不允许集合元素重复。
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表
维护元素的次序,这使得元素看起来是以添加顺序
保存的。
LinkedHashSet插入性能略低
于 HashSet,但在迭代访问
Set 里的全部元素时有很好的性能。
红黑树
结构存储数据自然排序
和定制排序
。默认情况下,TreeSet 采用自然排序。
自然排序
:TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列。
定制排序
:如果元素所属的类没有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其它属性大小进行排序,则考虑使用定制排序。定制排序,通过Comparator接口来实现。需要重写compare(T o1,T o2)方法。
同一个类的对象
。两个对象是否相等的唯一标准
是:两个对象通过 compareTo(Object obj) 或compare(Object o1,Object o2)
方法比较返回值。返回值为0,则认为两个对象相等。现实生活与开发中,我们常会看到这样的一类集合:用户ID与账户信息、学生姓名与考试成绩、IP地址与主机名等,这种一一对应的关系,就称作映射。Java提供了专门的集合框架用来存储这种映射关系的对象,即java.util.Map
接口。
Map与Collection并列存在。用于保存具有映射关系
的数据:key-value
Collection
集合称为单列集合,元素是孤立存在的(理解为单身)。Map
集合称为双列集合,元素是成对存在的(理解为夫妻)。Map 中的 key 和 value 都可以是任何引用类型的数据。但常用String类作为Map的“键”。
Map接口的常用实现类:HashMap
、LinkedHashMap
、TreeMap
和``Properties。其中,HashMap是 Map 接口使用
频率最高`的实现类。
这里主要以HashMap为例说明。HashMap中存储的key、value的特点如下:
Map 中的 key用Set来存放
,不允许重复
,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法
key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value,不同key对应的value可以重复
。value所在的类要重写equals()方法。
key和value构成一个entry。所有的entry彼此之间是无序的
、不可重复的
。
使用频率最高
的实现类。一维数组
+单向链表
+红黑树
进行key-value数据的存储。与HashSet一样,元素的存取顺序不能保证一致。判断两个key相等的标准
是:两个 key 的hashCode值相等,通过 equals() 方法返回 true。判断两个value相等的标准
是:两个 value 通过 equals() 方法返回 true。双向链表
来记录添加元素的先后顺序
,可以保证遍历元素时,与添加的顺序一致。有序状态
。红黑树
结构存储数据自然排序
:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException定制排序
:创建 TreeMap 时,构造器传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口两个key相等的标准
:两个key通过compareTo()方法或者compare()方法返回0。古老实现类
,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的。Properties 类是 Hashtable 的子类,该对象用于处理属性文件
由于属性文件里的 key、value 都是字符串类型,所以 Properties 中要求 key 和 value 都是字符串类型
存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法