前言
Java集合类是一种特别有用的工具类,可以实现常用的数据结构。
Java集合可以分为Set,List,Queue,Map四种体系,其中Set代表无序,不可重复的结合,List代表有序,可以重复的集合,Map代表具有映射关系的集合(键值对),Java 5 之后又添加了Queue,代表一种队列集合的实现。
集合类主要负责保存,盛装其他数据,因此集合类也被称为容器类。 所有集合类都位于java.util包下,后来为了处理多线程环境下的并发安全问题,Java 5 还在java.util.concurrent包下提供了一些多线程支持的集合类。
集合类和数组不一样,数组元素既可以是基本类型的值,也可以是对象(对象的引用变量);而集合里只能保存对象(对象的引用变量)。
Collection和Map是Java集合框架的根接口。
Collection
Set、List、Queue是Collection派生出的三个子接口,比较常用的:
HashSet,LinkedHashSetTreeSet是Set的实现类
ArrayList、LinkedList,Vector是List的实现类
ArrayDeque,LinkedList,PriorityQueue实现的Queue接口
Set
Set集合不允许包含相同的元素,如果试图把相同的元素加入到一个Set里,则添加操作失败,add()方法会返回fales,且新元素不会被加入。
HashSet类
HashSet按照Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet有以下特点:
- 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
- HashSet不是同步的,是线程不安全的。
- 集合元素值可能为null
HashSet判断两个元素相等的标准是两个对象通过equal()方法比较相等,且两个对象的hashcode()方法返回值也相等。
//类A中的equals()方法总是返回true,但是没有重写其hashCode()方法
Class A{
public boolean equals(Object obj){
return true;
}
}
//类B中的hashCode()方法总是返回1,但没有重写其equals()方法
Class B{
public int hashCode(){
return 1;
}
}
// 类C的hashCode()方法总是返回2,并且重写其equals()方法总是返回true
Class C{
public int hashCode(){
return 2;
}
public boolean equals(Object obj){
return true;
}
}
public class HashSetTest{
public static void main(String[] args){
var book = new HashSet();
//分别向book中添加两个A对象,两个B对象,两个C对象
book.add(new A());
book.add(new A());
book.add(new B());
book.add(new B());
book.add(new C());
book.add(new C());
System.out.println(books);
//结果:[B@1,B@1,C@2,A@5483cd,A@9931f5]
}
}
因此:
只有当equals()返回ture,且hashCode()返回值相同时,hashSet才会认为是同一个对象
LinkedHashSet
LinkedHashSet 是HashSet的子类,以链表形式维护元素的顺序,故相比于HashSet,LinkedHashSet是有序的。
TreeSet
- TreeSet是使用红黑树存储元素的,根据元素的实际大小来决定存储顺序,而不是由插入顺序决定的。
- TreeSet中的元素是有序的,所以相较于其他Set,增加了访问第一个,前一个,后一个,和最后一个的方法,以及提供了三个从TreeSet截取子TreeSet的方法
Object first(): 返回第一个元素
Object last(): 返回最后一个元素
Object lower(Object obj): 返回小于指定元素的最大元素,即上一个元素
Object higher(Object obj): 返回大于置顶元素的最小元素,即下一个元素
SortedSet subSet(Object from, Object to) 返回from到to之间的Set的子集合
SortedSet headSet(Object to) 返回小于to的Set的子集合
SortedSet tailSet(Object from) 返回大于等于from的Set的子集合
Set的性能分析
HashTree的性能总是比TreeSet的性能好,特别是常用的添加、查询等操作。因为TreeSet需要一个额外的红黑树来维持插入元素的顺序。只有当需要一个保持排序的Set的时候,才应使用TreeSet。
LinkedHashSet在插入和删除的时候,比HashSet慢,但是在查询,遍历的时候,会比HashSet快。
Set都是线程不安全的。HashSet底层是用HashMap存储的,HashMap同样线程不安全。