HashSet、TreeSet、LinkedHashSet的区别
1、HashSet
1.实现方式:基于哈希表(HashMap)实现
2.不允许重复,可以有一个null元素
3.不保证顺序恒久不变
4.添加元素时把元素作为HashMap的key存储,HashMap的value使用一个固定的Object对象
5.排除重复元素是通过equals来判断元素是否相同
6.判断两个对象是否相同,先判断两个对象的hashCode是否相同(如果两个对象的hashcode相同,不一定是同一个对象,如果不同,那一定不是同一个对象),如果不同,则两个对象不是同一个对象,如果相同还要进行equals判断,equals相同则是同一个对象,不同则不是同一个对象
7.自定义对象要重写hashcode方法和equals对象
小结:
(1)哈希表的存储结构:数组加链表,数组里的每个元素以链表的形式存储
(2)如何把对象存储到哈希表中,先计算对象的hashCode值,再对数组的长度求余数,来决定对象要存储在数组中的哪个位置
(3)解决hashSet中的重复值使用的方式是,参考第6点
基本使用:
写一个实体类(重新equals和hashcode方法)
class Cat { private String name; private int age; private int id; public Cat(String name, int age, int id) { this.name = name; this.age = age; this.id = id; } // get,set,toString() // 需要重写hashcode()和equals()方法 @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Cat cat = (Cat) o; return age == cat.age && id == cat.id && name.equals(cat.name); } @Override public int hashCode() { return Objects.hash(name, age, id); } }
使用HashSet:
private static void hashSet() { Set<String> set = new HashSet<>(); set.add("飞飞"); set.add("亮亮"); // 不可重复 set.add("亮亮"); set.add("关关"); set.add("曹操"); set.add("备备"); set.add(null); set.add(null); String[] strings = set.toArray(new String[]{}); for (String s : strings ) { System.out.println(s); } Cat c1 = new Cat("miaomiao", 4, 1); Cat c2 = new Cat("huahua", 3, 2); Cat c3 = new Cat("tom", 5, 3); // 需要重写hashcode()方法和equals方法 Cat c4 = new Cat("tom", 5, 3); Set<Cat> cats = new HashSet<>(); cats.add(c1); cats.add(c2); cats.add(c3); cats.add(c4); //cats.add(c4); System.out.println(cats.size()); }
2、TreeSet
1、有序的,基于TreeMap(二叉树数据结构),对象需要比较大小,通过对象比较器来实现
2、对象比较器还可以用来去除重复元素,如果自定义的类,没有实现比较器接口,将无法添加到TreeSet集合中
基本使用:
*/ private static void treeSet() { Cat c1 = new Cat("miaomiao", 4, 1); Cat c2 = new Cat("huahua", 3, 2); Cat c3 = new Cat("tom", 5, 3); Cat c4 = new Cat("Tom", 4, 1); //指定排序规则,先按照id,再年龄,再姓名 Set<Cat> cats = new TreeSet<>((o1, o2) -> { if (o1.getId() != o2.getId()) { return o1.getId() - o2.getId(); } if (o1.getAge() != o2.getAge()) { return o1.getAge() - o2.getAge(); } return o1.getName().compareTo(o2.getName()); }); cats.add(c1); cats.add(c2); cats.add(c3); cats.add(c4); System.out.println(cats); }
3、LinkedHashSet
1、哈希表和链表列表来实现
2、维护着一个运行与所有条目的双重链表列表,此链表定义了迭代顺序,即按照将元素插入到set中的顺序(插入顺序)进行迭代
简单使用:
private static void linkedHashSet(){ Cat c1 = new Cat("miaomiao", 4, 1); Cat c2 = new Cat("huahua", 3, 2); Cat c3 = new Cat("tom", 5, 3); Cat c4 = new Cat("Tom", 4, 1); Set<Cat> cats = new LinkedHashSet<>(); cats.add(c1); cats.add(c2); cats.add(c3); cats.add(c4); System.out.println(cats); }
4、如何选择?
如果要排序,选择TreeSet
如果不要排序,也不要保证顺序,选择HashSet
如果不要排序,要保证顺序,选择LinkedHashSet