set接口
java.util.Set 接口和List接口一样,同样继承自Collection接口,它与collection接口中的方法基本一致,并没有对collection接口进行功能上的拓展,只是比collection接口更加严格了,与List不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
Set接口特点:
1.不允许存储重复元素
2.没有索引,没有带索引的方法,也不能使用普通for循环,可以采用增强for,或者是迭代器。
HashSet介绍
java.util.HashSet 是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的,即存取顺序不一致。java.util.HashSet的底层实现其实是一个java.util.HashMap.
HashSet特点:
1.不允许存储重复元素
2.没有索引,没有带索引的方法,也不能使用普通for循环,可以采用增强for,或者是迭代器。
3.是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4.底层是一个哈希表结构(查询的速度非常快)
注意:
hashSet是根据对象的哈希值来确定在集合中的存储位置,因此具有良好的存取和查找性能,保证元素唯一的方式依赖于equals和hashCode方法。
代码:
public class HashSetDemo {
public static void main(String[] args) {
//创建一个Set集合
Set<Integer> set = new HashSet<>();
//使用add方法添加元素
set.add(1);
set.add(3);
set.add(2);
set.add(1); //存储重复元素
System.out.println(set);
//使用迭代器遍历set集合
Iterator<Integer> it = set.iterator();
while (it.hasNext()){
Integer n = it.next();
System.out.println(n);
}
//使用增强for遍历
for(Integer i:set){
System.out.println(i);
}
}
}
hashCode
哈希值:是一个十进制的整数,由系统随机给出,就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是数据的实际存储的物理地址。
在object类中有一个方法,可以获取对象的哈希值, int hashCode() 返回该对象的哈希码值
hashCode方法 public native int hashCode() native 代表方法调用的是本地操作系统的方法
代码演示:
定义persion类
public class Persion {
}
测试类:
public class Test {
public static void main(String[] args) {
//Psesion类是object类的子类 所以可以使用hashCode方法
Persion p1 = new Persion();
int h1 = p1.hashCode();
System.out.println(h1);
Persion p2 = new Persion();
System.out.println(p2.hashCode());
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());
}
}
HashSet存储自定义类型元素
给hashSet中存放自定义元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证hashSet集合中的对象唯一。
代码演示:
自定义学生类并重写hashCode和equals方法
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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 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);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试:
public static void main(String[] args) {
//创建一个Set集合
HashSet<Student> set = new HashSet<>();
//存储自定义类型的独享
Student s1 = new Student("于谦", 48);
set.add(s1);
set.add(new Student("郭德纲",45));
set.add(new Student("郭麒麟",27));
set.add(new Student("于谦", 48)); //自定义类型重写了hashCOde和equals方法后无法存入相同对象
//System.out.println(set);
//遍历
for(Student s:set){
System.out.println(s);
}
}
LinkedHashSet
在hashSet下面有一个子类 linkedHashSet,它是链表和哈希表组合的一个数据存储结构
特点
底层是一个哈希表+链表,多了一个链表(记录元素的存取顺序)保证元素有序
代码演示:
public class LinkedHashSetDemo {
public static void main(String[] args) {
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("bbb");
set.add("aaa");
set.add("abc");
set.add("bbc");
System.out.println(set);
Iterator<String> it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}