Java中的==与equals()

在Java中,我们使用==和equals的目的是为了比较两个数据是否相等,然而,对于不同的数据类型,“相等”有不同的含义。对于基本数据类型,我们所期待的相等是指两个基本类型的值相等;对于引用类型,我们所期待的相等是指这两个引用是否引用同一个对象,或者引用对象的值知否相等。下面我们针对这个问题展开。

Java的数据类型

1.基本数据类型

Java中一共有8种基本数据类型:

  • 整型:byte(1byte)、short(2byte)、int(3byte)、long(byte)
  • 浮点型:float(4byte),double(8byte)
  • 字符:char(2 byte)
  • 布尔型:boolean(没有给出精确的定义)

我们在声明一个基本数据类型变量时,这个变量直接指向基本数据类型的原始值。

每一种基本数据类型都有各自的封装类,如Integer等,封装类为各自基本数据类型提供了一些操作方法,可以直接使用。

2.引用数据类型

  • 类(class)
  • 接口(interface)
  • 数组(array)

我们声明一个引用数据类型的变量时,这个变量存储指向对象的地址单元,并不存储对象的原始值。

==的说明

==是Java的一个关系运算符,它的作用是判断两者是否相等,具体的作用方式是直接判断值是否相等。==既可以判断基本数据类型,又可以判断引用数据类型。对于基本数据类型来说,由于基本数据类型变量存储的都是原始值,==在判断变量是否相等时也是直接比较变量的值,所以如果基本变量的原始值相同,那么这两个变量使用==判断就输出true,例如:

public class Test{
    public static void main(String[] args){
        int a = 2;
        int b = 2;
        int c = 3;
        System.out.println("a==b? " + (a==b));
        System.out.println("a==c? " + (a==c));
    }
}

运行结果为:

a == b? true
a == c? false

然而,如果将基本数据类型封装成各自的封装类,情况又不相同,此处不再细说。

对于引用数据类型,也可以使用==来判断,由于引用数据类型变量存储的是引用对象的地址,所以使用==来比较两个引用数据类型变量,实际上是在比较这两个引用变量是否引用了同一个对象,例如:

public class Test{
    public static void main(String[] args){
        Object a = new Object();
        Object b = new Object();
        System.out.println("a==b? " + (a==b));
    }
}

运行结果为:

a == b? false

因为a和b没有指向相同的引用,所以a!=b,如果改变b的引用,结果就会有所不同:

public class Test{
    public static void main(String[] args){
        Object a = new Object();
        Object b = a;
        System.out.println("a==b? " + (a==b));
    }
}

此时输出结果为:

a == b? true

由此可以得知,当两个引用变量指向相同的对象时,==的判断才会为true

equals()的说明

equals()只能判断引用数据类型是否相等,因为所有的引用类型都继承自object类,而object类中定义了equals()方法,所以每一个类都继承了equals()方法。根据不同类对equals方法重载的不同,不同类的equals()方法的使用原理有所不同。在object类中,equals()方法定义如下:

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

可以看出,equals()方法实际上还是使用了==来判断,判断的还是两个引用类型变量是否引用同一对象。但是有些object子类例如StringDate等,对equals方法进行了重载,这时候就不仅仅是简单地比较是否引用同一个对象,例如String类中的equals方法如下:

 public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (!COMPACT_STRINGS || this.coder == aString.coder) {
                return StringLatin1.equals(value, aString.value);
            }
        }
        return false;
    }

String类对equals()方法重载后,equals()方法就不仅仅是简单地判断两个字符串是否引用同一个字符串对象,而是比较引用的两个字符串的值是否相等。

String的特别说明

我们先来看一段程序

 public static void main(String args[]){
        String a1 = "a";
        String a2 = "a";
        System.out.println(a1.equals(a2));
        System.out.println(a1==a2);
    }

运行结果为:

true
true

String是引用数据类型,它重载了equals()方法,所以比较的是a1和a2指向的字符串的值,equals()方法返回true没有问题。令人费解的是,为什么使用==也返回true呢?原因在于,String常量在Java中存储在字符串常量池中,当我们使用String str = "hello";创建字符串时,虚拟机首先会在字符串常量池中寻找是否已经存在“hello”常量,若存在则将此常量的引用直接返回给变量,否则创建“hello”常量,并返回该常量的引用。如果我们使用String str = new String("hello");创建字符串,虚拟机则会在非字符串常量池中创建字符串对象,并不会把“hello”引入到字符串常量池中,并将该字符串的引用返回给字符串变量。下面的程序说明了第二种创建字符串的方法:

 public static void main(String args[]){
        String a1 = "a";
        String a2 = new String("a");
        System.out.println(a1.equals(a2));
        System.out.println(a1==a2);
    }

运行结果为:

true
false

总结

  • ==:针对基本数据类型,直接比较原始值,原始值相等,返回true;针对引用数据类型,比较变量是否引用同一个对象,引用相同的对象返回true
  • equals():只能用于引用数据类型的比较,若未重载该方法,比较原理和==一样;若重载该方法,比较原理会有所不同
  • String要特别注意,建议使用equals()方法比较字符串
posted @ 2020-04-01 16:25  XJKunnn  阅读(227)  评论(0编辑  收藏  举报