java集合类源码分析之Set详解
Set集合与List一样,都是继承自Collection接口,常用的实现类有HashSet和TreeSet。值得注意的是,HashSet是通过HashMap来实现的而TreeSet是通过TreeMap来实现的,所以HashSet和TreeSet都没有自己的数据结构,具体可以归纳如下:
•Set集合中的元素不能重复,即元素唯一
•HashSet按元素的哈希值存储,所以是无序的,并且最多允许一个null对象
•TreeSet按元素的大小存储,所以是有序的,并且不允许null对象
•Set集合没有get方法,所以只能通过迭代器(Iterator)来遍历元素,不能随机访问
1.HashSet
下面给出HashSet的部分源码,以理解它的实现方式。
staticfinallongserialVersionUID=-5024744406713321676L; privatetransientHashMapmap; //DummyvaluetoassociatewithanObjectinthebackingMap privatestaticfinalObjectPRESENT=newObject();
观察源码,我们知道HashSet的数据是存储在HashMap的实例对象map中的,并且对应于map中的key,而Object类型的引用PRESENT则是对应于map中的value的一个虚拟值,没有实际意义。联想到HashMap的一些特性:无序存储、key值唯一等等,我们就可以很自然地理解Set集合元素不能重复以及HashSet无序存储的特性了。
下面从源代码的角度来理解HashSet的基本用法:
•构造器(四种)
1.HashSet()空的构造器,初始化一个空的HashMap
2.HashSet(Collectionc)传入一个子集c,用于初始化HashMap
3.HashSet(intinitialCapacity,floatloadFactor)初始化一个空的HashMap,并指定初始容量和加载因子
4.HashSet(intinitialCapacity)初始化一个空的HashMap,并指定初始容量
publicHashSet(){ map=newHashMap<>(); } publicHashSet(Collectionc){ map=newHashMap<>(Math.max((int)(c.size()/.75f)+1,16)); addAll(c); } publicHashSet(intinitialCapacity,floatloadFactor){ map=newHashMap<>(initialCapacity,loadFactor); } publicHashSet(intinitialCapacity){ map=newHashMap<>(initialCapacity); }
•插入元素
1.add(Ee)插入指定元素(调用HashMap的put方法实现)
SethashSet=newHashSet (); hashSet.add("D"); hashSet.add("B"); hashSet.add("C"); hashSet.add("A");
•查找元素
1.contains(Objecto)判断集合中是否包含指定的元素(调用HashMap的containsKey方法实现)
publicbooleancontains(Objecto){ returnmap.containsKey(o); }
2.由于HashSet的实现类中没有get方法,所以只能通过迭代器依次遍历,而不能随机访问(调用HashMap中keySet的迭代器实现)
publicIteratoriterator(){ returnmap.keySet().iterator(); }
应用示例:
SethashSet=newHashSet (); hashSet.add("D"); hashSet.add("B"); hashSet.add("C"); hashSet.add("A"); for(Iteratoriterator=hashSet.iterator();iterator.hasNext();){ Stringstring=(String)iterator.next(); System.out.print(string+""); }//DABC
•修改元素
由于HashMap中的key值不能修改,所以HashSet不能进行修改元素的操作
•删除元素
1.remove(Objecto)删除指定元素(调用HashMap中的remove方法实现,返回值为true或者false)
publicbooleanremove(Objecto){ returnmap.remove(o)==PRESENT; }
2.clear()清空元素(调用HashMap中的clear方法实现,没有返回值)
publicvoidclear(){ map.clear(); }
2.TreeSet
TreeSet是SortedSet接口的唯一实现类。前面说过,TreeSet没有自己的数据结构而是通过TreeMap实现的,所以TreeSet也是基于红黑二叉树的一种存储结构,所以TreeSet不允许null对象,并且是有序存储的(默认升序)。
privatetransientNavigableMapm; //DummyvaluetoassociatewithanObjectinthebackingMap privatestaticfinalObjectPRESENT=newObject();
上述源代码中的NavigableMap是继承自SrotedMap的一个接口,其实现类为TreeMap,因此TreeSet中的数据是通过TreeMap来存储的,此处的PRESENT也是没有实际意义的虚拟值。
下面从源代码的角度来理解HashSet的基本用法:
•构造器(四种)
1.TreeSet()空的构造器,初始化一个空的TreeMap,默认升序排列
2.TreeSet(Comparatorcomparator)传入一个自定义的比较器,常常用于实现降序排列
3.TreeSet(Collectionc)传入一个子集c,用于初始化TreeMap对象,默认升序
4.TreeSet(SortedSet
publicTreeSet(){ this(newTreeMap()); } publicTreeSet(Comparatorcomparator){ this(newTreeMap<>(comparator)); } publicTreeSet(Collectionc){ this(); addAll(c); } publicTreeSet(SortedSet s){ this(s.comparator()); addAll(s); }
应用示例
//自定义一个比较器,实现降序排列 SettreeSet=newTreeSet (newComparator (){ @Override publicintcompare(Integero1,Integero2){ //return0;//默认升序 returno2.compareTo(o1);//降序 } }); treeSet.add(200); treeSet.add(120); treeSet.add(150); treeSet.add(110); for(Iteratoriterator=treeSet.iterator();iterator.hasNext();){ Integerinteger=(Integer)iterator.next(); System.out.print(integer+""); }//200150120110
ArrayListlist=newArrayList (); list.add(300); list.add(120); list.add(100); list.add(150); System.out.println(list);//[300,120,100,150] //传入一个子集,默认升序排列 TreeSet treeSet=newTreeSet (list); for(Iteratoriterator=treeSet.iterator();iterator.hasNext();){ Integerinteger=(Integer)iterator.next(); System.out.print(integer+""); }//100120150300
/* *传入一个有序的子集,采用子集的比较器 *注意子集的类型必须是SortedSet及其子类或者实现类,否则将采用默认的比较器 *所以此处subSet的类型也可以是TreeSet。 */ SortedSetsubSet=newTreeSet (newComparator (){ @Override publicintcompare(Integero1,Integero2){ //return0;//默认升序 returno2.compareTo(o1);//降序 } }); subSet.add(200); subSet.add(120); subSet.add(150); subSet.add(110); for(Iteratoriterator=subSet.iterator();iterator.hasNext();){ Integerinteger=(Integer)iterator.next(); System.out.print(integer+""); }//200150120110 System.out.println(); Set treeSet=newTreeSet (subSet); for(Iteratoriterator=treeSet.iterator();iterator.hasNext();){ Integerinteger=(Integer)iterator.next(); System.out.print(integer+""); }//200150120110 System.out.println(); treeSet.add(500); treeSet.add(100); treeSet.add(105); for(Iteratoriterator=treeSet.iterator();iterator.hasNext();){ Integerinteger=(Integer)iterator.next(); System.out.print(integer+""); }//500200150120110105100
•插入元素
1.add(Ee)插入指定的元素(调用TreeMap的put方法实现)
2.addAll(Collectionc)插入一个子集c
ArrayListlist=newArrayList (); list.add(300); list.add(120); list.add(100); list.add(150); System.out.println(list);//[300,120,100,150] Set treeSet=newTreeSet (); //插入一个子集,默认升序 treeSet.addAll(list); for(Iteratoriterator=treeSet.iterator();iterator.hasNext();){ Integerinteger=(Integer)iterator.next(); System.out.print(integer+""); }//100120150300
•查找元素
1.contains(Objecto)判断集合中是否包含指定对象(调用TreeMap的containsKey方法实现)
2.与HashSet一样,TreeSet的实现类中没有get方法,所以只能通过迭代器依次遍历,而不能随机访问(调用TreeMap中keySet的迭代器实现)。
•修改元素
TreeSet不能进行修改元素的操作,原因与HashSet一样。
•删除元素
1.remove(Objecto)删除指定元素(调用TreeMap中的remove方法实现,返回true或者false)
publicbooleanremove(Objecto){ returnm.remove(o)==PRESENT; }
2.clear()清空元素(调用TreeMap中的clear方法实现,无返回值)
publicvoidclear(){ m.clear(); }
应用示例:
ArrayListlist=newArrayList (); list.add(300); list.add(120); list.add(100); list.add(150); System.out.println(list);//[300,120,100,150] Set treeSet=newTreeSet (); //插入一个子集,默认升序 treeSet.addAll(list); for(Iteratoriterator=treeSet.iterator();iterator.hasNext();){ Integerinteger=(Integer)iterator.next(); System.out.print(integer+""); }//100120150300 System.out.println(treeSet.remove(100));//true for(Iteratoriterator=treeSet.iterator();iterator.hasNext();){ Integerinteger=(Integer)iterator.next(); System.out.print(integer+""); }//120150300 treeSet.clear(); System.out.println(treeSet.size());//0
至此,HashSet和TreeSet的存储结构及基本用法介绍完毕。
以上这篇java集合类源码分析之Set详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。