当前位置: 代码迷 >> 综合 >> Java面试 每日一题:hashCode、equals、==
  详细解决方案

Java面试 每日一题:hashCode、equals、==

热度:68   发布时间:2023-12-02 10:35:32.0

==

它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 "= =’'比较的是值,引用数据类型==比较的是内存地址)
基本类型有:

  • byte(1字节):Byte
  • short(2字节):Short
  • int(4字节):Integer
  • long(8字节):Long
  • float(4字节):Float
  • double(8字节):Double
  • char(2字节):Character
  • boolean(未知):Boolean
Integer a=new Integer(5);
Integer b=new Integer(5);
int c=5;
int d=5;
System.out.println(c==d); //true
System.out.println(a==b); //falseSystem.out.println(a.equals(b)); //trueSystem.out.println(c==b); //true

装箱和拆箱

装箱:自动将基本数据类型转换为包装器类型
拆箱:自动将包装器类型转换为基本数据类型

在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法

valueOf:
IntegerCache为Integer类的缓存类,默认缓存了-128~127的Integer值,如遇到[-128,127]范围的值需要转换为Integer时会直接从IntegerCache中获取,具体如以下源码:

public static Integer valueOf(int i) {
    
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

从代码中我们可以通过设置java.lang.Integer.IntegerCache.high来设置缓存最大值,最终取值为Maths.max(high, 127)

-Djava.lang.Integer.IntegerCache.high=255

缓存池

new Integer(123) 与 Integer.valueOf(123) 的区别在于:

  • new Integer(123) 每次都会新建一个对象;
  • Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
Integer x = new Integer(123);
Integer y = new Integer(123);
System.out.println(x == y); // false
Integer z = Integer.valueOf(123);
Integer k = Integer.valueOf(123);
System.out.println(z == k); // true

valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。
基本类型对应的缓冲池如下:

  • boolean values true and false
  • all byte values
  • short values between -128 and 127
  • int values between -128 and 127
  • char in the range \u0000 to \u007F

在使用这些基本类型对应的包装类型时,如果该数值范围在缓冲池范围内,就可以直接使用缓冲池中的对象。
在 jdk 1.8 所有的数值类缓冲池中,Integer 的缓冲池 IntegerCache 很特殊,这个缓冲池的下界是 - 128,上界默认是 127,但是这个上界是可调的,在启动 jvm 的时候,通过 -XX:AutoBoxCacheMax= 来指定这个缓冲池的大小,该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界。

intValue:

public int intValue() {
    
return value;
}

equals

equals是顶层父类Object的方法之一
它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

  • 情况 1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
  • 情况 2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
// 你看,object默认调用的== , 你对象如果不重写,可能会发上重大事故
public boolean equals(Object obj) {
    
return (this == obj);
}

integer重写equals方法

public boolean equals(Object obj) {
    
if (obj instanceof Integer) {
    
return value == ((Integer)obj).intValue();
}
return false;
}

顺带说一下Object的hashcode方法

// Returns a hash code value for the object.
// 说白了,返回的就是该对象的地址值
public native int hashCode();

integer重写hashcode方法

public int hashCode() {
    
return Integer.hashCode(value);
}

例子

public class test1 {
    public static void main(String[] args) {
    String a = new String("ab"); // a 为一个引用String b = new String("ab"); // b 为另一个引用,对象的内容一样String aa = "ab"; // 放在常量池中String bb = "ab"; // 从常量池中查找if (aa == bb) // trueSystem.out.println("aa==bb");if (a == b) // false,非同一对象System.out.println("a==b");if (a.equals(b)) // trueSystem.out.println("aEQb");if (42 == 42.0) {
     // trueSystem.out.println("true");}}
}

说明

  • String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
  • 当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

hashCode

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在 JDK 的 Object.java 中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)
当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

hashCode与equals

  1. 如果两个对象相等,则 hashcode 一定也是相同的
  2. 两个对象相等,对两个对象分别调用 equals 方法都返回 true
  3. 两个对象有相同的 hashcode 值,它们也不一定是相等的
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

hashcode的例子:

public static void main(String[] args) {
    
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(1);
System.out.println(set.toString());
}

在添加1的时候,先判断hashcode是否相同,如果相同,继续判断equals比较值,这样的好处是,如果hashcode相同就直接返回false了,减少了一次equals的判断,因为通常hashcode的值判断是否相等比较快,而equals相对于hashcode来讲慢一些。所以,如果不重写hashcode,我们看到object的hashcode是对象的内存值,那么set添加1判断的时候,hashcode永远不相等,那么就永远返回false,不管添加1,还是2,都是false。

  相关解决方案