【Java】== 和 equals() 区别

本文详细介绍了Java中字符串的比较方式,包括基本类型和引用类型比较,以及字符串池的作用。通过实例演示了字符串引用与内容的比较,并探讨了字符串池如何优化字符串常量的内存管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

==

==可以用于基本类型和引用类型的比较,比较基本类型时,是比较其值是否相同;比较引用类型时,是比较其是否引用了同一对象(其实也是比较其值是否相同,这里的值是对象的地址)。例如:

int a = 1;
System.out.println(a == 1);             // true

String s1 = "hello";
String s2 = s1;
System.out.println(s1 == s2);           // true

String s3 = "hello";
String s4 = new String("hello");       
System.out.println(s1 == s3);           // true
System.out.println(s1 == s4);           // false

字符串s1的引用被被指给s2,所以s1s2引用相同,s1 == s2判断为true

其中s1 == s3结果为true,这个与JVM工作机制有关,后面会解释。

s4虽然内容与s1相同,但它是新创建的字符串对象,具有与s1不同的地址(即引用),所以s1 == s4判断为false

equals()

equals()用于比较两个对象的内容是否相同,例如:

String s1 = "hello";
String s4 = new String("hello"); 
System.out.println(s1 == s4);           // false
System.out.println(s1.equals(s4));      // true

根据前面解释,我们知道s1s4是不用的两个引用,但是他们的内容相同,所以s1.equals(s4)判断为true

equals()是基类Object的一个方法,其默认实现如下(摘自java SDK源码),可见默认调用==来比较。

public boolean equals(Object obj) {
    return (this == obj);
}

如果没有override该方法,那么就退化为和==相同的功效了。但是一般都会override该方法,用来比较两个对象内容是否相同,例如Stringequals()会比较字符串序列是否相同,所以,如果要比较对象内容是否相同用equals,对于自定义对象,根据需要override该方法。

字符串池

下面代码中,字符串s1 == s3true,表示他们都引用了相同对象,这与new String("hello")差异在哪里呢?

String s1 = "hello";
String s3 = "hello"; 
String s4 = new String("hello");       
System.out.println(s1 == s3);           // true
System.out.println(s1 == s4);           // false

JVM中有一个称为”字符串池”的共享区域,用来保存字符串常量,每当创建字符串常量时,会先查找字符串池,如果找到返回其引用,如果不存在则创建一个新的字符串,并添加到字符串池中。注意:该规则仅针对字符串常量,对于通过new创建的字符串没有该规则。

字符串常量,包括字面值(literal strings)和常量表达式(string-valued constant expressions),例如:

String s1 = "hello";                            // 字符串常量
String s2 = "h" + "e" + "l" + "l" + "o";        // 字符串常量
System.out.println(s1 == s2);           // true
System.out.println(s1.equals(s2));      // true

String s3 = "hello" + s1;                       // 非字符串常量

s1 = "hello"由于是字符串常量,创建时又不存在,所以创建时会被添加到字符串池中,当创建s2时,由于s2也是一个字符串常量(虽然是拼接而成,但每个组成部分都是常量,在编译时就可以确定,所以其也是字符串常量),其创建时会先查找字符串池,找到并返回引用,该引用与s1相同,所以s1 == s2比较为true,自然equals()比较也为true

可见定义多个相同的字符串常量值,其只占用一份内存空间,只会被创建一次,性能上好些。

java.lang.String中 equals() 的实现

最后一起看看java.lang.String类的equals()的源码,主要看下其实现原理和方法,方便我们为自定义类重写equals()方法时提供参考。

// java/lang/String.java
public boolean equals(Object anObject) {
    if (this == anObject) {            
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

首先判断引用是否相同,如果引用相同,那么内容必然相同,直接返回true。接下来判断比较对象是否是String类的一个实例,这样做是为了保证被比较对象类型一致(如果比较的两个对象是继承关系,这里也视作类型不同),类型一致后,比较字符串的长度,如果长度相同则比较字符串的每个字符,如果每个字符都相同返回true,对于其他情况都返回false

为自定义类重写 equals() 方法

通过前面的学习,对equals()有了一些了解,下面通过为自己的类重写equals()方法来巩固一下。代码如下:

class MyInteger {
    private int mValue;

    public MyInteger(int v) {
        mValue = v;
    }

    public int getValue() { return mValue; }

    public int hashCode() { return mValue; }

    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }  

        if (obj instanceof MyInteger) {
            MyInteger i = (MyInteger)obj;
            if (mValue == i.getValue()) {
                return true;
            }
        }

        return false;
    }
}

public class Test {
    public static void main (String [] args) {
        MyInteger i1 = new MyInteger(100);
        MyInteger i2 = new MyInteger(100);
        System.out.println(i1 == i2);               // false
        System.out.println(i1.equals(i2));          // true
    }
}

MyInteger是一个很简单的类,其只包含一个int类型的成员变量,在equals()中,我仿照java.lang.String类,先判断引用是否相同,如果相同直接返回true,如果引用不相同,再判断被比较对象是否是MyInteger类型,如果是再比较成员变量mValue是否相同,如果相同返回true,其他情况返回false

也许你注意到了,我还定义了一个hashCode()成员函数,这是JDK中要求的,查看java.lang.Objectequals()方法说明,其中提到重写equals()方法时,一般也需要重写hashCode()(我感觉是必须啊,不然编译不过–!)。而且要保证如果两个对象使用equals()比较相同,则被比较的两个对象的hashCode()返回值也必须相同,反之亦然。

在自定义的MyInteger中由于只有一个成员变量,可以直接在hashCode()的实现中直接返回该成员变量,这样可以保证上面所说的要求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值