了解哈希
哈希概念
把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。
哈希存储中的碰撞
对不同的关键字可能得到同一哈希值,即key1≠key2,而f(key1)=f(key2),这种现象称碰撞
哈希值
是jdk根据对象的内存地址或字符串或数字通过哈希函数计算出来的int类型的数值。
hashset,hashtable,hashMap的的去重
对自定义的引用对象去重需要什么操作?
重写equals方法 和 重写HashCode方法
什么是去重?(以Set为例)
去重即判断两个对象是否相等,相等则将对象归为一个
1.会先调用对象的hashcode方法获得hash值,如果set中哈希表里没有对应的hash值,则将此对象存入set中
2.如果set中hash表里有对应的hash值,就让后面的对象调用equals方法,和之前的hash值不同的对象进行比较,如果返回为true就证明已经存在,不再存储,如果返回为false,则视为新对象,加入到set中。
为什么一定要重写HashCode和equals方法?
自定义一个引用对象类,并且只实现HashCode和equals方法中的任意一个,可以发现相同的对象在集合中会认为是不同的
对象的添加:
public class test {
public static void main(String[] args) {
Set<Phone> set=new HashSet<>();
set.add(new Phone("xiaomi", 799));
set.add(new Phone("xiaomi", 799));
set.add(new Phone("xiaomi", 799));
set.add(new Phone("xiaomi", 799));
System.out.println(set.size());
System.out.println();
}}
Phone类和重写方法的实现:
public class Phone {
private String brand;
private double price;
public Phone() {
}
public Phone(String brand, double price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Phone [brand=" + brand + ", price=" + price + "]";
}
@Override //重写 hashCode()方法
public int hashCode() {
// TODO Auto-generated method stub
int prime = 31;
int resultCode = prime * (prime + 1) + (brand == null?0:brand.hashCode());
//以对象的品牌名字符串产生的哈希值进行数学运算得到最终的哈希值
return resultCode;
}
// equals方法是object的方法。
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
// 内存地址 引用传递是否相等
if (this == obj) {
return true;
}
// 空判断 如果对象为空对象则为一个新的对象 并且存储在哈希表中
if (obj == null) {
return false;
}
// 是否同属于一个类
if (getClass() != obj.getClass()) {
return false;
}
Phone myPhone = (Phone)obj;
// 判断属性 band price 是否和myPhone的相等
// price
if (this.price != myPhone.price) {//如果当前对象和phone对象价格不同则认为是一个新的对象 存储
return false;
}
// brand 引用类型 进行空判断
if (this.brand == null) {
if (myPhone.brand != null) {
return false;//如果当前对象品牌名为空 而phone对象不为空 则存储
}
}else if (!this.brand.equals(myPhone.brand)) {
return false;//如果品牌名不同则存储
}
return true;
}
}
只有这两种方法都重写了之后,运行结果则为1 否则均为4
开发中我们需要的自定义对象不是一种严格意义上的相等,而是一种业务上的对象相等,所以要重写equals方法
重写equals方法之后一定要重写HashCode方法,目的在于有两个相同对象equals返回为true的情况下,它们的hashcode也能够返回相同的值,不然总是会出问题