Java集合类源码之Set的具体分析
下面小编就为大家带来一篇java集合类源码分析之Set详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
Set集合与List一样,都是继承自Collection接口,常用的实现类有HashSet和TreeSet。值得注意的是,HashSet是通过HashMap来实现的而TreeSet是通过TreeMap来实现的,所以HashSet和TreeSet都没有自己的数据结构,具体可以归纳如下:
•Set集合中的元素不能重复,即元素唯一
•HashSet按元素的哈希值存储,所以是无序的,并且最多允许一个null对象
•TreeSet按元素的大小存储,所以是有序的,并且不允许null对象
•Set集合没有get方法,所以只能通过迭代器(Iterator)来遍历元素,不能随机访问
1.HashSet
下面给出HashSet的部分源码,以理解它的实现方式。
static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
观察源码,我们知道HashSet的数据是存储在HashMap的实例对象map中的,并且对应于map中的key,而Object类型的引用PRESENT则是对应于map中的value的一个虚拟值,没有实际意义。联想到HashMap的一些特性:无序存储、key值唯一等等,我们就可以很自然地理解Set集合元素不能重复以及HashSet无序存储的特性了。
下面从源代码的角度来理解HashSet的基本用法:
•构造器(四种)
1.HashSet() 空的构造器,初始化一个空的HashMap
2.HashSet(Collection extends E> c) 传入一个子集c,用于初始化HashMap
3.HashSet(int initialCapacity, float loadFactor) 初始化一个空的HashMap,并指定初始容量和加载因子
4.HashSet(int initialCapacity) 初始化一个空的HashMap,并指定初始容量
public HashSet() { map = new HashMap<>(); } public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); }
•插入元素
1.add(E e) 插入指定元素(调用HashMap的put方法实现)
Set<String> hashSet = new HashSet<String>(); hashSet.add("D"); hashSet.add("B"); hashSet.add("C"); hashSet.add("A");
•查找元素
1.contains(Object o) 判断集合中是否包含指定的元素(调用HashMap的containsKey方法实现)
public boolean contains(Object o) { return map.containsKey(o); }
2.由于HashSet的实现类中没有get方法,所以只能通过迭代器依次遍历,而不能随机访问(调用HashMap中keySet的迭代器实现)
public Iterator<E> iterator() { return map.keySet().iterator(); }
应用示例:
Set<String> hashSet = new HashSet<String>(); hashSet.add("D"); hashSet.add("B"); hashSet.add("C"); hashSet.add("A"); for (Iterator iterator = hashSet.iterator(); iterator.hasNext();) { String string = (String) iterator.next(); System.out.print(string+" "); }//D A B C
•修改元素
由于HashMap中的key值不能修改,所以HashSet不能进行修改元素的操作
•删除元素
1.remove(Object o) 删除指定元素(调用HashMap中的remove方法实现,返回值为true或者false)
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
2.clear() 清空元素(调用HashMap中的clear方法实现,没有返回值)
public void clear() { map.clear(); }
2.TreeSet
TreeSet是SortedSet接口的唯一实现类。前面说过,TreeSet没有自己的数据结构而是通过TreeMap实现的,所以TreeSet也是基于红黑二叉树的一种存储结构,所以TreeSet不允许null对象,并且是有序存储的(默认升序)。
private transient NavigableMap<E,Object> m; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
上述源代码中的NavigableMap是继承自SrotedMap的一个接口,其实现类为TreeMap,因此TreeSet中的数据是通过TreeMap来存储的,此处的PRESENT也是没有实际意义的虚拟值。
下面从源代码的角度来理解HashSet的基本用法:
•构造器(四种)
1.TreeSet() 空的构造器,初始化一个空的TreeMap,默认升序排列
2.TreeSet(Comparator super E> comparator) 传入一个自定义的比较器,常常用于实现降序排列
3.TreeSet(Collection extends E> c) 传入一个子集c,用于初始化TreeMap对象,默认升序
4.TreeSet(SortedSet
public TreeSet() { this(new TreeMap<E,Object>()); } public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); } public TreeSet(Collection<? extends E> c) { this(); addAll(c); } public TreeSet(SortedSet<E> s) { this(s.comparator()); addAll(s); }
应用示例
//自定义一个比较器,实现降序排列 Set<Integer> treeSet = new TreeSet<Integer>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // return 0; //默认升序 return o2.compareTo(o1);//降序 } }); treeSet.add(200); treeSet.add(120); treeSet.add(150); treeSet.add(110); for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); System.out.print(integer+" "); } //200 150 120 110
ArrayList<Integer> list = new ArrayList<Integer>(); list.add(300); list.add(120); list.add(100); list.add(150); System.out.println(list); //[300, 120, 100, 150] //传入一个子集,默认升序排列 TreeSet<Integer> treeSet = new TreeSet<Integer>(list); for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); System.out.print(integer+" "); }//100 120 150 300
/* * 传入一个有序的子集,采用子集的比较器 * 注意子集的类型必须是SortedSet及其子类或者实现类,否则将采用默认的比较器 * 所以此处subSet的类型也可以是TreeSet。 */ SortedSet<Integer> subSet = new TreeSet<Integer>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // return 0; //默认升序 return o2.compareTo(o1);//降序 } }); subSet.add(200); subSet.add(120); subSet.add(150); subSet.add(110); for (Iterator iterator = subSet.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); System.out.print(integer+" "); } //200 150 120 110 System.out.println(); Set<Integer> treeSet = new TreeSet<Integer>(subSet); for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); System.out.print(integer+" "); }//200 150 120 110 System.out.println(); treeSet.add(500); treeSet.add(100); treeSet.add(105); for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); System.out.print(integer+" "); }//500 200 150 120 110 105 100
• 插入元素
1.add(E e) 插入指定的元素(调用TreeMap的put方法实现)
2.addAll(Collection extends E> c) 插入一个子集c
ArrayList<Integer> list = new ArrayList<Integer>(); list.add(300); list.add(120); list.add(100); list.add(150); System.out.println(list); //[300, 120, 100, 150] Set<Integer> treeSet = new TreeSet<Integer>(); //插入一个子集,默认升序 treeSet.addAll(list); for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); System.out.print(integer+" "); }//100 120 150 300
•查找元素
1.contains(Object o) 判断集合中是否包含指定对象(调用TreeMap的containsKey方法实现)
2.与HashSet一样,TreeSet的实现类中没有get方法,所以只能通过迭代器依次遍历,而不能随机访问(调用TreeMap中keySet的迭代器实现)。
•修改元素
TreeSet不能进行修改元素的操作,原因与HashSet一样。
•删除元素
1.remove(Object o) 删除指定元素(调用TreeMap中的remove方法实现,返回true或者false)
public boolean remove(Object o) { return m.remove(o)==PRESENT; }
2.clear() 清空元素(调用TreeMap中的clear方法实现,无返回值)
public void clear() { m.clear(); }
应用示例:
ArrayList<Integer> list = new ArrayList<Integer>(); list.add(300); list.add(120); list.add(100); list.add(150); System.out.println(list); //[300, 120, 100, 150] Set<Integer> treeSet = new TreeSet<Integer>(); //插入一个子集,默认升序 treeSet.addAll(list); for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); System.out.print(integer+" "); }//100 120 150 300 System.out.println(treeSet.remove(100));//true for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); System.out.print(integer+" "); }//120 150 300 treeSet.clear(); System.out.println(treeSet.size());//0
至此,HashSet和TreeSet的存储结构及基本用法介绍完毕。
Atas ialah kandungan terperinci Java集合类源码之Set的具体分析. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Panduan untuk Square Root di Java. Di sini kita membincangkan cara Square Root berfungsi di Java dengan contoh dan pelaksanaan kodnya masing-masing.

Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

Panduan untuk Penjana Nombor Rawak di Jawa. Di sini kita membincangkan Fungsi dalam Java dengan contoh dan dua Penjana berbeza dengan contoh lain.

Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

Panduan untuk Nombor Armstrong di Jawa. Di sini kita membincangkan pengenalan kepada nombor Armstrong di java bersama-sama dengan beberapa kod.

Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah
