1.Set接口的介绍(记住)
java.util.Set<E>接口 extends Collection<E>接口
Set接口的特点:
1.不允许存储重复的元素 add(1) add(1)==>集合中只有一个1
2.不包含带索引的方法,里边的方法和Collection接口一模一样
2.HashSet集合的介绍和基本使用(重点)
package com.itheima.demo04Set;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
/*
java.util.HashSet<E> implements Set<E>接口
HashSet集合的特点:
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。
它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
1.不允许存储重复的元素
2.不包含带索引的方法(get,set,remove)==>不能使用普通for循环遍历
3.是一个无序的集合:存储的元素和取出的元素[有可能]不一致
4.底层是一个哈希表结构
JDK1.8版本之前:数组+单向链表
JDK1.8版本之后:数组+单向链表|数组+红黑树
*/
public class Demo01HashSet {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("aaa");
set.add("bbb");
set.add("aaa");
set.add("ccc");
set.add("ddd");
System.out.println(set);//[aaa, ccc, bbb, ddd]
HashSet<Integer> set2 = new HashSet<>();
Collections.addAll(set2,1,2,3,4,5);
System.out.println(set2);//[1, 2, 3, 4, 5]
//使用迭代器遍历Set集合
Iterator<String> it = set.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("------------------------");
//使用增强for循环遍历Set集合
for (String s : set) {
System.out.println(s);
}
}
}
3.哈希值(扩展知识点)
package com.itheima.demo04Set;
/*
哈希值(扩展知识点_了解)
Obejct类有一个方法:
int hashCode() 返回该对象的哈希码值。
哈希值:就是一个十进制的整数,由操作系统返回
hashCode方法底层源码:
public native int hashCode();
native:本地方法,调用不是java语言写的方法,调用操作系统(其他语言)底层的方法
toString方法源码:对象的地址值
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
Integer.toHexString(hashCode()):把十进制(0-9)的整数,转换为十六进制(0-9,a-f)
----------------------------------------------------------------------------------
hashCode返回的对象的地址值,是一个假的虚拟的地址(看着玩),不是对象实际在内存中地址
*/
public class Demo02HashCode{
public static void main(String[] args) {
Person p1 = new Person();
int h1 = p1.hashCode();
System.out.println(h1);//1163157884==>1
System.out.println(p1.toString());//com.itheima.demo04Set.Person@4554617c==>1
Person p2 = new Person();
System.out.println(p2.hashCode());//1956725890==>1
System.out.println(p2.toString());//com.itheima.demo04Set.Person@74a14482==>1
System.out.println(p1==p2);//比较的两个对象的实际地址 false
}
}
package com.itheima.demo04Set;
public class Person extends Object{
//重写Object类的hashCode方法
@Override
public int hashCode() {
return 1;
}
}
4.String类的哈希值(扩展知识点)
package com.itheima.demo04Set;
/*
String类的哈希值(扩展知识点_了解)
String类重写了Object类的hashCode方法
规则:
相同的字符串,返回的哈希值是一样的
不同的字符串,返回的哈希值也有可能一样
*/
public class Demo03StringHashCode {
public static void main(String[] args) {
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
System.out.println('a'+0);//97
System.out.println('重'+0);//37325
}
}
5.HashSet集合存储数据的结构(哈希表)
6.使用HashSet集合存储String不重复的原理(扩展知识点)
package com.itheima.demo04Set;
import java.util.HashSet;
/*
使用HashSet集合存储String不重复的原理(扩展知识点_了解)
String类(Integer,Double...)重写了Object类的hashCode方法和equals方法,用于判断元素是否重复
*/
public class Demo04HashSetSaveString {
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);
}
}
7.HashSet存储自定义类型元素(重点中的重点)
同名同年龄的Student对象,视为重复的元素,只能存储一个
Student类重写hashCode方法和equals方法,来保证元素不重复
快捷键:alt+insert==>选择 equals() and hashCode()
package com.itheima.demo04Set;
import java.util.HashSet;
/*
HashSet存储自定义类型元素(重点中的重点)
自定义类型:Student,Person,Animal...
要求:同名同年龄的学生只能存储一次(不重复)
解决:
自定义类型重写hashCode方法和equals方法保证元素唯一
*/
public class Demo05HashSetStudent {
public static void main(String[] args) {
HashSet<Student> set = new HashSet<>();
Student s1 = new Student("a",10);
Student s2 = new Student("a",10);
System.out.println(s1.hashCode());//1163157884==>107
System.out.println(s2.hashCode());//1956725890==>107
set.add(s1);
set.add(s2);
Student s3 = new Student("b",9);
set.add(s3);
for (Student s : set) {
System.out.println(s.getName()+"\t"+s.getAge());
}
}
}
package com.itheima.demo04Set;
public class Student {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
/*
重写Object类的hashCode方法:了解
name.hashCode()+age;
---------------------------------------
Student s1 = new Student("a",10);
Student s2 = new Student("a",10);
set.add(s1);计算s1的哈希值 97+10=107 在集合中找有没有107这个哈希值的元素,发现没有,直接把s1存储到集合中
set.add(s2);计算s2的哈希值 97+10=107 在集合中找有没有107这个哈希值的元素,发现有,s2.equals(s1)==>true
两个元素的哈希值相同,equals返回true,认定两个元素相同,不会把s2存储到Set集合中
--------------------------------------------------------------------------------
Student s3 = new Student("b",9);
set.add(s3);计算s2的哈希值 98+9=107 在集合中找有没有107这个哈希值的元素,发现有,s3.equals(s1)==>false
两个元素的哈希值相同,equals返回false,认定两个元素不同,会把s3存储到Set集合中
--------------------------------------------------------------------------------
降低不同元素出现相同哈希值的概率
name.hashCode()*2+age;
set.add(s1);计算s1的哈希值 97*2+10=204
set.add(s3);计算s3的哈希值 98*2+9=205 发现集合中没有205这个哈希值的元素,直接存储到集合中
name.hashCode()*31+age;
*/
/*@Override
public int hashCode() {
return name.hashCode()+age;
}*/
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
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;
}
}
8.LinkedHashSet集合(了解)
package com.itheima.demo04Set;
import java.util.HashSet;
import java.util.LinkedHashSet;
/*
java.util.LinkedHashSet<E>集合extends HashSet<E>集合
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。
特点:
1.不允许存储重复的元素
2.不包含带索引的方法(get,set,remove)==>不能使用普通for循环遍历
3.是一个有序的集合
4.底层是哈希表+单向链表==>底层就组成双向链表结构
JDK1.8版本之前:数组+单向链表+单向链表
JDK1.8版本之后:数组+单向链表|数组+红黑树+单向链表
*/
public class Demo06LinkedHashSet {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("aaa");
set.add("bbb");
set.add("aaa");
set.add("ccc");
set.add("ddd");
System.out.println(set);//[aaa, ccc, bbb, ddd] 不允许重复,无序集合
LinkedHashSet<String> linked = new LinkedHashSet<>();
linked.add("aaa");
linked.add("bbb");
linked.add("aaa");
linked.add("ccc");
linked.add("ddd");
System.out.println(linked);//[aaa, bbb, ccc, ddd] 不允许重复,有序集合
}
}