集合
集合综述
Java 集合就像一种容器,可以把多个对象的引用放入容器中。
Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组
Java 集合可分为 Set、List 和 Map 三种体系
- Set:无序、不可重复的集合
- List:有序,可重复的集合
- Map:具有映射关系的集合
在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 Java5 增加了泛型以后,Java 集合可以记住容器中对象的数据类型
Iterator
-
Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
-
所有实现了Collection接口的集合类都有一个Iterator()方法,用以返回一个实现了Iterator接口的对象,即返回一个迭代器
-
Iterator仅用于遍历集合,Iterator本身并不存放对象
TreeSet<Student> treeSet = new TreeSet<Student>(); Iterator<Student> it2 = treeSet.iterator(); while (it2.hasNext()) { System.out.println(it2.next()); }
Ps:(遍历集合所有元素时)在调用it.next()方法之前必须要调用it.hasNext()进行检测,若不调用,下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常
ArrayList集合
- ArrayList实现了长度可变的数组,在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高
- 线程不安全
- 动态扩容方式是“50%
ps:使用无参构造器,初始elementDate容量为0,第一次添加elementDate扩容为10,如需再次扩容,则扩容为elementDate的1.5倍
使用指定大小构造器,初始elementDate容量为指定大小,如需扩容则直接扩容为elementDate容量1.5倍
LinkedList集合
LinkedList采用双向链表存储方式。插入、删除元素时效率比较高
void addFirst(Object e):将制定元素插入该双向队列的开头。
void addLast(Object e):将制定元素插入该双向队列的末尾。
Iterator descendingIterator():返回以该双向队列对应的迭代器,该迭代器将以逆向顺序来迭代队列中的元素。
Object getFirst():获取、但不删除双向队列的第一个元素。
Object getLast(): 获取、但不删除双向队列的最后一个元素。
boolean offerFirst(Object e): 将指定的元素插入该双向队列的开头。
boolean offerLast(Object e): 将指定的元素插入该双向队列的末尾。
Object peekFirst(): 获取、但不删除该双向队列的第一个元素:如果此双端队列为空,则返回null。
Object peekLast():获取、但不删除该双向队列的最后一个元素:如果此双端队列为空,则返回null。
Object pollFirst():获取、并删除该双向队列的第一个元素:如果此双端队列为空,则返回null。
Object pollLast():获取、并删除该双向队列的最后一个元素:如果此双端队列为空,则返回null。
Object pop():pop出该双向队列所表示的栈中第一个元素。
void push(Object e):将一个元素push进该双向队列所表示的栈中(即该双向队列的头部)。
Object removerFirst():获取、并删除该双向队列的最后一个元素。
Object removeFirstOccurrence(Object o):删除该双向队列的第一次的出现元素o。
Object removeLast():获取、并删除该双向队列的最后一个元素。
Object removeLastOccurrence(Object o):删除该双向队列的最后一次出现的元素o。
Vector集合
- Vector实现了长度可变的数组,在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高
- 线程安全
- 动态扩容方式是“倍增”
ps:使用无参构造器,初始elementDate容量为0,第一次添加elementDate扩容为10,如需再次扩容,则扩容为elementDate的2倍
使用指定大小构造器,初始elementDate容量为指定大小,如需扩容则直接扩容为elementDate容量2倍
Vector,ArrayList,LinkedList区别与联系
说明:程序中示范了LinkedList作为双向队列、栈和List集合的用法。LinkedList与ArrayList、Vector的实现机制完全不同,ArrayList、Vector内部以数组的形式来保存集合中的元素,因此随机访问集合元素上有较好的性能;而LinkedList内部以链表的形式来保存集合中的元素,因此随机访问集合时性能较差,但在插入、删除元素时性能非常出色(只需改变指针所指的地址即可)。Vector因实现了线程同步功能,所以各方面性能有所下降。
关于使用List集合的几点建议:
如果需要遍历List集合元素,对应ArrayList、Vector集合,则应该使用随机访问方法(get)来遍历集合元素,这样性能更好。对应LinkedList集合,则应采用迭代器(Iterator)来遍历集合元素。
如果需要经常执行插入、删除操作来改变Lst集合大小,则应该使用LinkedList集合,而不是ArrayList。
如果多条线程需要同时访问List集合中的元素,可以考虑使用Vector这个同步实现。
Set集合
Set集合不允许重复元素,是因为Set判断两个对象相同不是使用==运算符,而是根据equals方法。即两个对象用equals方法比较返回true,Set就不能接受两个对象。
ps:Set接口中的知识,同时也适用于HashSet、TreeSet两个实现类。
equals()与==的区别
==对于基本类型,比较的是值,但对于引用类型,比较的是内存地址
equals对于引用类型,参考源码
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
首先,equals会用==比较两个类型在内存中的地址一不一样,如果一样,则直接返回true,如果不一样,则直接往下走,再判断是否为string类型,如果不是,则强转为string类型,再将字符串数组拆分为单个字符,一一比较,有一个不相同,则返回false,否则返回true
HashSet集合
HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。
HashSet的特点:
(1)HashSet不是同步的,多个线程访问是需要通过代码保证同步
(2)集合元素值可以使null。
HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值也相等。
PS:
(1)Object类提供的toString方法总是返回该对象实现类的类名+@+hashCode(16进制数)值,所以可以看到上面程序输出的结果。可以通过重写toString方法来输出自己希望的形式。
(2)即使2个A对象通过equals比较返回true,但HashSet依然把它们当成2个对象;即使2个B对象的hashCode()返回相同值,但HashSet依然把它们当成2个对象。即如果把一个对象放入HashSet中时,如果重写该对象equals()方法,也应该重写其hashCode()方法。其规则是:如果2个对象通过equals方法比较返回true时,这两个对象的hashCode也应该相同。
TreeSet集合
TreeSet是SortedSet接口的唯一实现,TreeSet可以确保集合元素处于排序状态(元素是有序的)
value可以为null
- Comparator comparator(): 返回当前Set使用的Comparator,或者返回null,表示以自然方式排序。
- Object first():返回集合中的第一个元素。
- Object last():返回集合中的最后一个元素。
- Objiect lower(Object e):返回集合中位于指定元素之前的元素(即小于指定元素的最大元素,参考元素可以不是TreeSet的元素)。
- Object higher(Object e):返回集合中位于指定元素之后的元素(即大于指定元素的最小元素,参考元素可以不需要TreeSet的元素)。
- SortedSet subSet(fromElement, toElement):返回此Set的子集,范围从fromElement(包含大于等于)到toElement(不包含小于)。
- SortedSet headSet(toElement):返回此Set的子集,由小于toElement的元素组成。
- SortedSet tailSet(fromElement):返回此Set的子集,由大于或等于fromElement的元素组成
Map集合
- Map 用于保存具有映射关系的数据,因此 Map 集合里保存着两组值,一组值用于保存 Map 里的 Key,另外一组用于保存 Map 里的 Value
- Map 中的 key 和 value 都可以是任何引用类型的数据
- Map 中的 Key 不允许重复,即同一个 Map 对象的任何两个 Key 通过 equals 方法比较中返回 false
- Key 和 Value 之间存在单向一对一关系,即通过指定的 Key 总能找到唯一的,确定的 Value。
HashMap集合
Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
TreeMap集合
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。
HashTable类
Hashtable与 HashMap类似,它继承自Dictionary类,不同的是:它不允许记录的键或者值为空;
它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。
HashTable使用Enumeration,HashMap使用Iterator。
HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
Collections工具类
Collection与Collections的区别
Collection是个java.util下的接口,它是各种集合结构的父接口。
Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
Collections是个java.util下的类,它包含有各种有关集合操作的静态方法。
Collections 此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。它包含在 collection 上操作的多态算法,即“包装器”,包装器返回由指定 collection 支持的新 collection,以及少数其他内容。 如果为此类的方法所提供的 collection 或类对象为 null,则这些方法都会抛出 NullPointerException。