前言

相信大家一定在很多地方多看到过​​==​​与​​equals()​​的区别,也把区别讲的很详细,每次记住了,很快又会变得模糊不清。

这时就需要从原理深入剖析,一招制敌!

认识==的用法

在Java中,==的作用有两个

(1).基础数据类型:比较的是两者的值是否相等,比如int,float,double变量。

public static void main(String[] args) {
int a = 1;
int b = 1;
float x = 3.2f;
float y = 3.2f;
System.out.println(a == b);
System.out.println(x == y);
}

此时结果,两个都为true。

(2).引用数据类型:比较的是两者的地址是否相同,比如Integer等。String是一个特殊的,后面再讨论。

public static void main(String[] args) {
Integer a = new Integer(1);
Integer b = new Integer(1);
Integer c = 1;
System.out.println(a == b);
System.out.println(a == c);
}

此时结果,两个都为false。因为使用Integer类,每次都创建了新的对象,所以分配的地址是不同的。但Integer类与int作比较结果如何呢?

public static void main(String[] args) {
Integer a = new Integer(1);
Integer b = new Integer(1);
int c = 1;
System.out.println(a == b);//false
System.out.println(c == a);//true
System.out.println(c == b);//true
}

输出结果:false,true,true。此时我们不难发现,当包装类与其基本类型进行比较时,会转变为对两者的值的比较。

认识equals()的用法

equals()方法源自Object类,先看一下源码是什么样:

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

看到这里,很快就发现equals()方法和==是相同的,所以在使用基本数据类型和引用对象(包装类除外)比较时,两者不存在区别。

public static void main(String[] args) {
Integer a = new Integer(1);
Integer b = new Integer(1);
int c = 1;
System.out.println(a.equals(c));
System.out.println(b.equals(c));
}

此时结果为:true,true。当包装类与其基本类型用equals()方法进行比较时,同样比较两者的值,也不存在区别。

不同点

有一点是比较特殊的,在使用equals()方法对包装类和包装类进行比较时,则会不同。

public static void main(String[] args) {
Integer a = new Integer(1);
Integer b = new Integer(1);
System.out.println(a.equals(b));//true
System.out.println(a == b); //false
}

输出结果:true,false。包装类和包装类采用equals()方法,也会转变成对值得比较。为什么呢?因为包装类重写了Object类的equals()方法。打开重写后equals()方法的源码:

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

从这里可以看出,包装类和包装类的比较,就是两者值得比较。

String类中的==和equals()方法

在String中,重写了Object类的equals(),自然逻辑和功能不同了。

String类中的equals()方法

先来看看String类中equals()方法源码:

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。第二个判断中,若字符内容相同,则返回true。其实就是对两者值得比较。

public static void main(String[] args) {
String a = "Hello";
String b = "Hello";
System.out.println(a.equals(b));//true
}

输出结果:true。

String类中的测试

public static void main(String[] args) {
String a = "Hello";
String b = "Hello";
String c = new String("Hello");
String d = c;
System.out.println(a == b);//true
System.out.println(a == c);//false
System.out.println(c == d);//true

System.out.println(a.equals(b));//true
System.out.println(a.equals(c));//true
System.out.println(c.equals(d));//true
}

为什么出现这样的结果。可以从内存的角度来解释:

3.通过内存来解释

在Java中,一般是把​对象​放在​堆区​,对象的​引用​则放在了​栈区​。

深入解析==与equals()区别_java

从上图可以看出:

  • 当String a = “Hello”;创建一个引用类型a,指向堆区一个位置,用于保存字符串对象;

  • 当String b = “Hello”;java会到它的常量池中​​"hello"是不是在常量池中​已存在​。如果已经存在则​返回这个常量池中的"hello"的地址​(在java中叫引用)给变量b;

  • String c= new String(“hello world”); 会在堆区再次存放一个字符串对象;

  • String d = c;当中d和c是相同的引用,指向同一个地址。

所以根据此可以判断以上输出结果:

//true 指向同一个地址
System.out.println(a == b);

//false 指向不同地址
System.out.println\(a == c\);

//true 指向同一个地址
System.out.println\(c == d\);

//true 地址指向的内容相同
System.out.println\(a.equals\(b\)\);

//true 地址指向的内容相同
System.out.println\(a.equals©\);

//true 地址指向的内容相同
System.out.println\(c.equals\(d\)\);