特点:不能存储重复元素,没有下标,无序存取(怎么存的不一定怎么取)
例:
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