特点:不能存储重复元素,没有下标,无序存取(怎么存的不一定怎么取)
例:
public class Demo06 { public static void main(String[] args) { HashSet<String> set=new HashSet<String>(); set.add("abc"); set.add("abc"); for(String s:set){ System.out.println(s); } } }
运行结果为:
abc
set是一个接口,那我们就只能创建子类对象,就创建Hashset集合对象
HashSet集合的数据存储是存储在哈希表中,哈希表实际上数组和链表结构的结合。默认的数组长度为16,默认的加载因子为0.75,也就是说到数据存储到第16*0.75长度的时候,会自动再开辟一个长度为16的集合,那当然这个数组长度和加载因子也可以通过构造方法自定义指定,但最好使用默认的,比较科学。
图解:
HashSet集合的所有方法都是继承的collection接口中的方法,包括add等等,直接拿过来用就好
为什么不能存重复值
首先HashSet在调用add方法的时候,首先去调用你添加对象的类的Hashcode方法去计算hash值,再看集合中如果不存在这个hash值,那就存储这个对象,如果有这个hash值那就再调用equls方法去比较内容,如果内容不同,则存入,如果相同,则丢弃不存。
这个Hashcode方法,是根据他的算法返回一值。
例:打印一下这个hashcode的值
public class Demo07 { public static void main(String[] args) { System.out.println("abc".hashCode()); System.out.println("abc".hashCode()); System.out.println(new Person("a",10).hashCode()); System.out.println(new Person("a",10).hashCode()); } }
这里发现 前两个abc的hashcode值是一样的,后两个值不一样,是因为我们自定义Person类中没有重写Hashcode方法和equls方法,默认的调用的是object类中的这两个方法。前两个一样是因为string类中重写了这两个方法。
图解;abc的hash值的算法
利用这些特点,我们创建一个自定义类,记得重写方法
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; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person() { super(); } @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; } }
创建测试类测试
public class Demo06 { public static void main(String[] args) { // TODO Auto-generated method stub HashSet<String> set=new HashSet<String>(); set.add("abc"); set.add("abc"); for(String s:set){ System.out.println(s); } HashSet<Person> set2=new HashSet<Person>(); set2.add(new Person("a",10)); set2.add(new Person("a",10)); set2.add(new Person("b",9)); for(Person d:set2){ System.out.println(d.toString()); } } }
运行结果为
abc
Person [name=a, age=10]
Person [name=b, age=9]
图解:
因为set接口是无序存取,也就是说怎么存的不一定怎么取得,那set接口有一个子类LinkedHashSet结合,就是有序取值,怎么存的就是怎么取
代码展示:
public class Demo08 { public static void main(String[] args) { LinkedHashSet<String> set=new LinkedHashSet<String>(); set.add("b"); set.add("a"); for(String s:set){ System.out.println(s); } } }
运行结果为:
b
a