Set接口
java.util.Set接口 extends Collection接口
Set接口的特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,所以不能使用for循环
java.util.HashSet集合 implements Set接口
HashSet特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
3.是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4.底层是一个哈希表结构(查询的速度非常快)
public class Demo03Set {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(1);//set中不能使用重复元素
//使用迭代器遍历set集合
Iterator<Integer> it = set.iterator();
while (it.hasNext()){
Integer next = it.next();
System.out.println(next);
}
//使用foreach遍历
for (int a:set) {
System.out.println(a);
}
}
}
哈希值
哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)
在Object类中有一个方法,可以获取对象的哈希值
- int hashCode()返回该对象的哈希值
hashCode方法的源码:
- public native int hashCode();
native:代表该方法调用的是本地操作系统的方法
public class Demo01HashSet {
public static void main(String[] args) {
//Person类继承了Object类,所以可以使用Object类的hashCode方法
Person p1 = new Person();
int h1 = p1.hashCode();
System.out.println(h1);
Person p2 = new Person();
int h2 = p2.hashCode();
System.out.println(h2);
//类中hashCode方法重写后,它的地址值会变为你重写的方法的返回值
System.out.println(p1);
System.out.println(p2);
System.out.println(p1==p2);//false
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.hashCode());//96354
System.out.println(s2.hashCode());//96354
System.out.println("通话".hashCode());//1179395
System.out.println("重地".hashCode());//1179395
}
}
HashSet存储数据的结构哈希表
Set集合存储元素不能重复的原理
/*
* Set集合不允许重复元素的原理*/
public class Demo02HashSetSave {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
String s1 = new String("abc");
String s2 = new String("abc");
set.add(s1);
set.add(s2);
set.add("重地");
set.add("通话");
set.add("abc");
System.out.println(set);//[重地, 通话, abc]
}
}
HashSet存储自定义类型元素
package demohash;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, 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;
}
}
HashSet存储自定义类型元素
* set集合报错元素唯一:
* 存储的元素(String,Integer,...Student,Person...),必须重写hashCode方法和equals方法
* 要求:
* 同名同年龄的人,视为同一个人,只能存储一次。*/
public class Demo03HashSetSaveStudent {
public static void main(String[] args) {
//创建HashSet集合存储Person
HashSet<Student> stu = new HashSet<>();
Student p1 = new Student("小帅哥", 18);
Student p2 = new Student("小帅哥", 18);
Student p3 = new Student("小帅哥", 19);
System.out.println(p1.hashCode());
System.out.println(p2.hashCode());
stu.add(p1);
stu.add(p2);
stu.add(p3);
System.out.println(stu);
}
}
LinkedHashSet集合
/*java.util.LinkedHashSet集合 extends HashSet集合
* LinkedHashSet集合特点:
* 底层是一个哈希表(数组+链表/红黑树)+链表 :多一条链表(用来记录元素的存储数据),保证元素有序*/
public class Demo04LinkedHashSet {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("www");
set.add("abc");
set.add("abc");
set.add("itcast");
System.out.println(set);//[abc, www, itcast]无序,不允许重复
LinkedHashSet<String> lk = new LinkedHashSet<>();
lk.add("www");
lk.add("abc");
lk.add("abc");
lk.add("itcast");
System.out.println(lk);//[www, abc, itcast]有序,不允许重复
}
}