哈希值
import java.util.Objects;
public class Person extends Object {
//重写hashCode方法
@Override
public int hashCode() {
return 1;
}
}
/**
* 哈希值:是一个十进制整数,由系统随机给出(是模拟出来的地址,不是对象真正的物理地址)
* Object类有一个方法可以获得对象的哈希值
* hashCode方法源码:
* public native int hashCode();
* native :代表该方法调用的是本地操作系统的方法
*/
public class Demo01HashCode {
public static void main(String[] args) {
//Person类继承了Object类所以可以使用Object类的hashCode方法
Person p1=new Person();
int h1 = p1.hashCode();
System.out.println(h1);//1163157884
Person p2=new Person();
int h2 = p2.hashCode();
System.out.println(h2);//1956725890
/**
* toString源码
* return getClass().getName() + "@" + Integer.toHexString(hashCode());
*/
System.out.println(p1);//@4554617c 16进制的hashCode
System.out.println(p2);//@74a14482 16进制的hashCode
System.out.println(p1==p2);//false
/**
* String类的哈希值
* String类重写了Object类的hashCode方法
*/
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
}
}
哈希表
jdk1.8之前:
- 哈希表=数组+链表
jdk1.8之后:
- 哈希表=数组+链表
- 哈希表=数组+红黑树(提高查询速度)
哈希表的特点: 速度快
Set集合不允许存重复元素的原理
import java.util.HashSet;
/**
* Set集合不允许存重复元素的原理
*/
public class Demo02HashSetSaveString {
public static void main(String[] args) {
//创建HashSet集合对象
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);
}
}
原理解释:
1.set集合在调用add方法时,add方法会调用元素的hashCode方法和equals方法,判断元素是否重复
2. set.add(s1);
add方法会调用s1的hashCode方法计算出字符串"abc"的哈希值,哈希值是96354
在集合找有没有有没有96354这个哈希值的元素,发现没有
就会把s1存储到集合中
3.set.add(s2);
add方法会调用s2的hashCode方法计算出字符串"abc"的哈希值,哈希值是96354
在集合找有没有有没有96354这个哈希值的元素,发现有(哈希冲突)
s2会调用equals方法和哈希值相同的元素进行比较 s2.equals(s1),返回true
两个元素的哈希值相等,equals方法返回true,认定两个元素相同
就不会把s2存储到集合中
4.set.add(重地);
add方法会调用"重地"的hashCode方法计算出字符串"重地"的哈希值,哈希值是1179395
在集合找有没有有没有1179395这个哈希值的元素,发现没有
就会把重地存储到集合中
5.set.add(“通话”)
add方法会调用"通话"的hashCode方法计算出字符串"通话"的哈希值,哈希值是1179395
在集合找有没有有没有1179395这个哈希值的元素,发现有(哈希冲突)
"通话"会调用equals方法和哈希值相同的元素进行比较 “通话”.equals(“重地”),返回false
两个元素的哈希值相等,equals方法返回false,认定两个元素不相同
就不会把"通话"存储到集合中
注意:
set集合存储的元素必须重写hashCode方法和equals方法
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
= name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, );
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.util.HashSet;
/**
* hashSet存储自定义数据类型
* set集合报错元素唯一:
* 存储的元素,必须重写hashCode和equals方法
*
* 要求:
* 同名同年龄的人,视为同一个人,只能存储一次
*/
public class Demo03HashSetSavePerson {
public static void main(String[] args) {
//创建一个hashSet集合来存储Person
HashSet<Person> set=new HashSet<>();
Person p1=new Person("小娜",18);
Person p2=new Person("小娜",18);
Person p3=new Person("小娜",19);
System.out.println(p1.hashCode());//1163157884 23363974
System.out.println(p2.hashCode());//1956725890 23363974
System.out.println(p1==p2);//false false
System.out.println(p1.equals(p2));//false true
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);
}
}
LinkedHashSet
import java.util.HashSet;
import java.util.LinkedHashSet;
/**
* java.util.LinkedHashSet集合 继承 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("huhu");
System.out.println(set);//[abc, www, huhu] 无序 不允许重读
LinkedHashSet<String> linked=new LinkedHashSet<>();
linked.add("www");
linked.add("abc");
linked.add("abc");
linked.add("huhu");
System.out.println(linked);//[www, abc, huhu] 有序 不允许重读
}
}