Set接口 java.util.Set接口 extends Collection接口
Set接口的特点:
HashSet java.util.HashSet implements Set ,是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。java.util.HashSet底层的实现其实是一个java.util.HashMap支持
HashSet特点:
不允许存储重复的元素
没有索引,没有带索引的方法,也不能使用普通的for循环遍历
是一个无序的集合,存储元素和取出元素的顺序有可能不一致
底层是一个哈希表结构(查询的速度非常的快)
tips:
Set集合取出元素的方式可以采用:迭代器、增强for。
HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。
保证元素唯一性的方式依赖于:hashCode与equals方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void main (String[] args) { Set<Integer> set = new HashSet <>(); set.add(1 ); set.add(3 ); set.add(2 ); set.add(1 ); Iterator<Integer> it = set.iterator(); while (it.hasNext()){ Integer n = it.next(); System.out.println(n); } System.out.println("-----------------" ); for (Integer i : set) { System.out.println(i); } }
HashSet集合存储数据的结构(哈希表) 在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里 。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。
而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树 ,这样大大减少了查找时间。
HashSet 如何检查重复? 在 JDK1.8 中,HashSet
的add()
方法只是简单的调用了HashMap
的put()
方法,并且判断了一下返回值以确保是否有重复元素。直接看一下HashSet
中的源码:
1 2 3 4 5 public boolean add (E e) { return map.put(e, PRESENT)==null ; }
而在HashMap
的putVal()
方法中也能看到如下说明:
1 2 3 4 5 6 final V putVal (int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { ... }
也就是说,在 JDK1.8 中,实际上无论HashSet
中是否已经存在了某元素,HashSet
都会直接插入,只是会在add()
方法的返回值处告诉我们插入前是否存在相同元素。
HashSet加入元素时
哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,不是数据实际存储的物理地址)
int hashCode() :Object类的一个方法,返回该对象的哈希码值。
为什么HashSet存储自定义类型元素必须重写hashCode方法和equals方法 给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。
set集合报错元素唯一:存储的元素为(String,Integer,…Student,Person…)时,必须重写hashCode方法和equals方法 ,因为不同对象的地址值不相同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Demo01HashCode { public static void main (String[] args) { Person p1 = new Person (); int h1 = p1.hashCode(); System.out.println(h1); Person p2 = new Person (); int h2 = p2.hashCode(); System.out.println(h2); System.out.println(p1); System.out.println(p2); System.out.println(p1==p2); String s1 = new String ("abc" ); String s2 = new String ("abc" ); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); System.out.println("重地" .hashCode()); System.out.println("通话" .hashCode()); } }
例子
要求:同名同年龄的人视为同一个人,只能存储一次(若不重写,不同的对象必定可以重复存储)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public class Person { private String name; private int age; public Person () { } public Person (String name, int age) { this .name = name; this .age = age; } @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Person person = (Person) o; return age == person.age &&Objects.equals(name, person.name); } @Override public int hashCode () { return Objects.hash(name, age); } @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}' ; } } public static void main (String[] args) { HashSet<Person> set = new HashSet <>(); Person p1 = new Person ("小美女" ,18 ); Person p2 = new Person ("小美女" ,18 ); Person p3 = new Person ("小美女" ,19 ); System.out.println(p1.hashCode()); System.out.println(p2.hashCode()); System.out.println(p1==p2); System.out.println(p1.equals(p2)); set.add(p1); set.add(p2); set.add(p3); System.out.println(set); }
LinkedHashSet java.util.LinkedHashSet extends HashSet
底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序(插入顺序和取出顺序相同)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 HashSet<String> set = new HashSet <>(); set.add("www" ); set.add("abc" ); set.add("abc" ); set.add("itcast" ); System.out.println(set); LinkedHashSet<String> linked = new LinkedHashSet <>(); linked.add("www" ); linked.add("abc" ); linked.add("abc" ); linked.add("itcast" ); System.out.println(linked);
TreeSet java.util.TreeSet implements SortedSet
底层数据结构是二叉树(红黑树),采用自然排序或比较器排序保证元素有序(默认采用自认排序)
1 2 3 4 5 6 TreeSet<String> set = new TreeSet <>(); set.add("www" ); set.add("abc" ); set.add("abc" ); set.add("itcast" ); System.out.println(set);