set接口的特点:
1.不包含重复元素
2.set集合没有索引,只能用迭代器或增强for循环遍历
3.set的底层是map集合
方法和Collection的方法基本一样
set接口的实现类HashSet:
1.无序集合
2.可以存入空(null)
3.不可以存在重复元素
示例:
package demo; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class HashSetDemo { public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("abc1"); set.add("abc1"); set.add("abc2"); set.add("abc3"); set.add("abc4"); Iterator<String> i1 = set.iterator(); while(i1.hasNext()){ System.out.println(i1.next()); } } } /* 输出: 注意:这里的输出特点是无序的 abc1 abc4 abc2 abc3 */
set底层数据结构是哈希表:
特点:存储取出都比较快
原理:具体省略,简单说就是链表数组结合体
对象的哈希值:普通的一个整数
可以理解为身份证号,是hashset存储的依据
package demo; public class Person {}
package demo; public class HashDemo { public static void main(String[] args) { Person p = new Person(); int i = p.hashCode(); System.out.println(i); //每次运行都会输出不同的整数,比如1191201656 String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1.hashCode());//96354 System.out.println(s2.hashCode());//96354 //这里Stirng重写hashcode方法,有对应的计算公式 //当字符串的内容相同时候,运算结果就相同,因此s1和s2的哈希值相同 } }
哈希表存储过程:
1.调用对象的哈希值
2.集合在容器内搜索有没有重复的哈希值,如果没有,存入新元素,记录哈希值
3.再次存储,重复上边的过程
4.如果有重复的哈希值,调用后来者的equals方法,参数为前来者,结果得到true,集合判断为重复元素,不存入
相同的字符串如果存进去,哈希值相同,equals方法为true,不会存入相同的
只要哈希值相同或者equals方法为true都成立才不会存入,只要其中一条不满足,都会储存
哈希表存储自定义对象:
package demo; public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString() { return this.name + ":" + this.age; } public Person() { } public Person(String name, int age) { super(); this.name = name; this.age = age; } }
package demo; import java.util.HashSet; public class HashDemo { public static void main(String[] args) { HashSet<Person> setPerson = new HashSet<Person>(); setPerson.add(new Person("a",17)); setPerson.add(new Person("b",20)); setPerson.add(new Person("b",20)); setPerson.add(new Person("c",18)); System.out.println(setPerson); //[c:18, b:20, a:17, b:20] //发现存入了重复的元素 //所以想办法使name和age相同的Person对象视为同一个对象 //所以需要重写hashcode方法 } }
自己重写:
package demo; public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString() { return this.name + ":" + this.age; } public Person() { } public Person(String name, int age) { super(); this.name = name; this.age = age; } public int hashCode(){ return name.hashCode()+age*66; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (obj instanceof Person) { Person p = (Person) obj; return name.equals(p.name) && age == p.age; } return false; } }
eclipse可以帮助我们写:
package demo; public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString() { return this.name + ":" + this.age; } public Person() { } public Person(String name, int age) { super(); this.name = name; this.age = age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
LinkedHashSet集合:基于链表的哈希表实现,继承HashSet,它具有顺序
示例:
package demo; import java.util.LinkedHashSet; public class LinkedHashSetDemo { public static void main(String[] args) { //有序的set LinkedHashSet<Integer> link = new LinkedHashSet<Integer>(); link.add(1); link.add(2); link.add(3); link.add(4); System.out.println(link); //[1, 2, 3, 4] } }
关于hashcode和equals的一些问题,在面试中会问道:
1.两个对象哈希值相同,那么equals方法一定返回true吗?不一定
取决于如何重写equals,如果重写固定了它返回false,结果就一定是false
2.equals方法返回true,那么哈希值一定相同吗?一定
如果类中定义一个静态变量(static int a = 1),然后重写hashcode返回a+1,那么每一个对象的哈希值都不一样
不过java中规定:对象相等,必须具有相同的哈希码值,所以这里是一定的