equals 与 hashCode 笔记三

第三篇文章主要讲解相关“ equals 与 == ”面试题分析,分为以下部分:

  1. String类的“ equals 与 == ”
  2. Integer类的“ equals 与 == ”

String类的“ equals 与 == ”

在Java中对于字符串的创建,有两种形式:字符串常量和使用 new 来构造一个 String 对象。

字面量形式

在JVM中,为了减少对字符串变量的重复创建,其拥有一段特殊的内存空间,这段内存被称为字符串常量池。

比如 String str1 = "Hello" 创建了一个对象。此时默认字符串常量池中没有内容为“Hello”的对象存在。当JVM在字符串常量池中没有找到内容为 "Hello" 的对象时,就会创建一个内容为 "Hello" 的对象,并将它的引用返回给变量a。

当我们再次 String str2 = "Hello" 时,会发生什么情况呢?
首先JVM会在字符串常量池中查询是否有内容为 "Hello" 的对象。因为此时字符串常量池中已经有内容为 "Hello" 的对象了,故JVM不会创建新的地址空间,而是将原有的 "Hello" 对象的引用返回,所以此时变量 num1 和变量 num2 拥有的是同一个对象引用,即指向的是同一块内存地址。

使用 new 构造 String 对象

当我们 new 一个字符串对象时,不管字符串常量池中是否有内容相同的对象,JVM 都会创造一个新的对象,其内存地址均不同。
String str = new String("Hello")
创建过程分析:当执行String str = new String("Hello");时,JVM 首先在字符串常量池中查看是否存在字符串对象 "Hello",

  • 如果不存在该对象,则先在字符串常量池中创建一个新的字符串对象"Hello",然后执行new String("Hello")构造方法,在堆内存中创建一个新的字符串对象"Hello",并将引用 str 指向堆内存中创建的新对象;
  • 如果已存在该对象,则不用创建新的字符串对象"Hello",而直接使用字符串常量池中已存在的对象"Hello", 然后执行new String("Hello")构造方法,在堆内存里创建一个新的字符串对象 "Hello",并将引用 str 指向堆内存中创建的新对象。

测试代码:

public class EqualsTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
                
        String str1 = new String("Hello");
        String str2 = new String("Hello");
        String str3 = "Hello";
        String str4 = "Hel" + "lo";

        System.out.println("====== String equals ======");

        System.out.println("str1 == str2 : " + (str1 == str2));
        System.out.println("str1 == str3 : " + (str1 == str3));
        System.out.println("str1.equals(str2) : " + str1.equals(str2));
        System.out.println("str1.equals(str3) : " + str1.equals(str3));
        System.out.println("str1 == str4 : " + (str1 == str4));
        System.out.println("str1.equals(str4) : " + str1.equals(str4));
    }
}

测试结果:

====== String equals ======
str1 == str2 : false
str1 == str3 : false
str1.equals(str2) : true
str1.equals(str3) : true
str1 == str4 : false
str1.equals(str4) : true

Integer 类的“ equals 与 == ”

自动装箱与自动拆箱

自动装箱:将Java的基本类型转换成包装器类型
自动拆箱:将Java的包装器类型转换成基本类型

Java数据类型分为基本数据类型和包装器类型。
基本类型: short int long float double byte boolean char
包装器类型: Short Integer Long Float Double Byte Boolean Character

Integer num = 1 // 自动装箱 Java调用 Integer 的 valueOf(int) 方法来完成自动装箱的
int num1 = num // 自动拆箱 Java调用 Integer 的 intValue 方法来完成自动拆箱的

注意:对于 Integer 类型的对象来说,如果我们要创建的 Integer 对象的数值在 [-128,127]的区间之内,缓存中早已存储了该范围的值,那么JVM就会在缓存中查找,返回已经存在的对象的引用;超过此范围,JVM需要重新创建该对象。

测试代码:

public class EqualsTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        int num1 = 1;
        Integer num2 = 1;
        Integer num3 = 1;
        Integer num4 = 128;
        Integer num5 = 128;
        
        System.out.println("====== Integer equals ======");

        System.out.println("num1 == num2 : " + (num1 == num2));
        System.out.println("num2.equals(num1) : " + num2.equals(num1));
        System.out.println("num2 == num3 : " + (num2 == num3));
        System.out.println("num2.equals(num3) : " + num2.equals(num3));
        System.out.println("num4 == num5 : " + (num4 == num5));
        System.out.println("num4.equals(num5) : " + num4.equals(num5));
    }
}

测试结果:

====== Integer equals ======
num1 == num2 : true
num2.equals(num1) : true
num2 == num3 : true
num2.equals(num3) : true
num4 == num5 : false
num4.equals(num5) : true

参考链接

java中String对象的创建过程和JVM中的状态分析