赞
踩
Set:不允许重复的集合。不会有多个元素引用相同的对象。
- public class HashSet<E> extends AbstractSet<E>
- implements Set<E>, Cloneable, java.io.Serializable
- public class LinkedHashSet<E> extends HashSet<E>
- implements Set<E>, Cloneable, java.io.Serializable {
- public class TreeSet<E> extends AbstractSet<E>
- implements NavigableSet<E>, Cloneable, java.io.Serializable
HashSet底层是基于HashMap实现的,元素是无序的,添加、删除操作复杂度跟HashMap都是o(1)。Map——传送门
部分源码如图。
- // Dummy value to associate with an Object in the backing Map
- private static final Object PRESENT = new Object();
- //默认构造函数,实例化一个空的HashMap对象,初始容量16,负载因子0.75
- 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);
- }
- //采用map.keySet()的迭代器
- public Iterator<E> iterator() {
- return map.keySet().iterator();
- }
- public int size() {
- return map.size();
- }
- public boolean isEmpty() {
- return map.isEmpty();
- }
- //set里面放的key-value的key,这里是containsKey
- public boolean contains(Object o) {
- return map.containsKey(o);
- }
- //add方法,是把Map键值对的形式,构造PRESENT为null添加进去
- public boolean add(E e) {
- return map.put(e, PRESENT)==null;
- }
- public void clear() {
- map.clear();
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
从上面源码中可以看出,当HashSet集合中添加元素(add方法)时,相当于Map调用put方法,而Map的put方法要求key不能重复。其实本质上是调用对象的HashCode()方法,来获得对象的HashCode值,根据HashCode值决定存放位置。在Java中,每个对象都有HashCode()方法,存储的是对象在JVM堆上的内存地址,并且都不相同,HashMap中重写了hashCode()和equals() 方法,感兴趣可以去研究下。
public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}
Java规范中
重写equals方法,必须重写hashCode方法,对象相同即equals返回true,hashCode必须相同,如果对象不相同即equals返回false,hashCode可能相同。
HashSet常用方法代码示例
- package Set;
-
-
- import java.util.HashSet;
- import java.util.Iterator;
-
- public class HashSetDemo {
- public static void main(String[] args) {
- HashSet<Integer> set = new HashSet<>();
- set.add(1);
- set.add(3);
- set.add(3);
- //添加重复元素
- System.out.println("添加重复元素:" + set.add(1));
- //输出set大小
- System.out.println("set大小:" + set.size());
- //判断是否包含值
- System.out.println("是否包含1:" + set.contains(1));
- //删除值3
- set.remove(3);
- System.out.println("删除3之后的set:" + set);
-
- set.add(88);
- set.add(666);
- //遍历set
- //1、foreach遍历
- for (Integer num : set) {
- System.out.print(num + " ");
- }
- System.out.println();
- //2、迭代器遍历
- Iterator<Integer> it = set.iterator();
- while (it.hasNext()) {
- System.out.print(it.next() + " ");
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
继承HashSet,底层由哈希表+双向链表组成,保证了迭代顺序,元素有序且唯一,存取顺序一致,类似于LinkedHashMap,只不过保证元素不重复。
- //四个构造函数
- public LinkedHashSet(int initialCapacity, float loadFactor) {
- super(initialCapacity, loadFactor, true);
- }
- public LinkedHashSet(int initialCapacity) {
- super(initialCapacity, .75f, true);
- }
- public LinkedHashSet() {
- super(16, .75f, true);
- }
- public LinkedHashSet(Collection<? extends E> c) {
- super(Math.max(2*c.size(), 11), .75f, true);
- addAll(c);
- }
-
- //上面构造函数中的super函构造函数
- HashSet(int initialCapacity, float loadFactor, boolean dummy) {
- //实例化一个LinkedHashMap
- map = new LinkedHashMap<>(initialCapacity, loadFactor);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
LinkedHashSet没有自己方法,所有方法继承自HashSet,唯一不同的是采用不同对象存储元素,LinkedHashSet存储的是LinkedHashMap的键。
LinkedHashSet常用方法代码示例
- package Set;
-
- import java.util.LinkedHashSet;
-
- public class LinkedHashSetDemo {
- public static void main(String[] args) {
- LinkedHashSet<Integer> lset = new LinkedHashSet<>();
- lset.add(1);
- lset.add(88);
- lset.add(66);
- //重复元素
- System.out.println("重复元素添加:" + lset.add(88));
- ;
- lset.add(9999);
- //foreach遍历,可以看到结果按插入顺序输出
- for (Integer num : lset) {
- System.out.print(num + " ");
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
底层是红黑树,非线程安全,对元素排序时,如果采用空参构造函数则自然排序,否则采用比较器排序。 类似TreeMap
默认自然排序示例代码如下
- package Set;
-
- import java.util.Iterator;
- import java.util.TreeSet;
-
- public class TreeSetDemo {
- public static void main(String[] args) {
- TreeSet<Integer> set = new TreeSet<>();
- set.add(8);
- set.add(1);
- set.add(6);
- set.add(2);
- Iterator<Integer> it = set.iterator();
- //按照key值排序过的
- while (it.hasNext()) {
- System.out.print(it.next() + " ");
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
这里key为什么能够自然排序,其实是Integer类继承了Comparable接口
public final class Integer extends Number implements Comparable<Integer>
如果要排序的key值类型没有实现排序,那么程序就会运行报错,如下图会报错
- package Set;
-
- import java.util.Iterator;
- import java.util.TreeSet;
-
- public class TreeSetDemo {
- static class bird {
- int age;
-
- public bird(int age) {
- this.age = age;
- }
- }
-
- public static void main(String[] args) {
- TreeSet<bird> set = new TreeSet<>();
- set.add(new bird(8));
- set.add(new bird(1));
- set.add(new bird(2));
- set.add(new bird(6));
- Iterator<bird> it = set.iterator();
- ///这里key值是bird类,本身是无序的,虽然编译没错,但是TreeSet是有序的
- //所以这样运行时会报错的bird cannot be cast to java.lang.Comparable
- while (it.hasNext()) {
- System.out.print(it.next() + " ");
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Comparable接口排序示例代码如下
- package Set;
-
- import java.util.Iterator;
- import java.util.TreeSet;
-
- public class TreeSetDemo {
- static class bird implements Comparable<bird> {
- int age;
-
- public bird(int age) {
- this.age = age;
- }
-
- public int getAge() {
- return this.age;
- }
-
- @Override
- public int compareTo(bird b) {
- return this.age - b.age;
- }
- }
-
- public static void main(String[] args) {
- TreeSet<bird> set = new TreeSet<>();
- set.add(new bird(8));
- set.add(new bird(1));
- set.add(new bird(2));
- set.add(new bird(6));
- Iterator<bird> it = set.iterator();
- ///这里key值是bird类,本身是无序的,虽然编译没错,但是TreeSet是有序的
- //所以这样运行时会报错的bird cannot be cast to java.lang.Comparable
- while (it.hasNext()) {
- System.out.print(it.next().getAge() + " ");
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
未完待续......
本博客是个人学习总结,参考学习了很多知识(网络&源码&书),如果内容有误或者有资料参考未列举出来,欢迎交流~
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2019.12.14 更新
set,map,list相互转换
- Map<String, String> map = new HashMap<String, String>();
- map.put("sss", "sssss");
- List<String> list = new ArrayList<String>(map.keySet());
- System.out.println(list);
- list.add("sss");
- System.out.println(list);
- Set<String>set=new HashSet<String>(list);
- System.out.println(set);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。