由于之前也没好好刻意去记二者的区别,但是发现经常会用到这些,有时自己也用错,于是特地再次总结记忆,若能帮助到你,就更好了!
想要熟练掌握equals与==的用法与区别,前提必须掌握基本数据类型和引用类型的概念,讲二者区别之前,先大概讲解一下基本数据类型和引用类型的概念,当然,有一定基础的朋友可直接略过!
基本数据类型和引用类型
八大基本数据类型:
Byte,short,int,long,double,folat,boolean,char
.
其中byte占一个字节,short和char占两个字节,int,float占四个字节,double和long占8个字节,boolean只有true和false,这八种数据变量中直接存储值
注意:八大基本数据类型对应着各自的封装类型的包装类,提供了更多的方法,且不进行初始化时值默认为空(基本数据类型必须初始化),并且属于引用类型
引用类型:
引用类型主要是一些类、接口、数组
引用类型变量中存储的是地址,对应的地址存储数据
"=="和equals()方法的区别和联系
"=="比较基本数据类型时比较的是表面值内容,而比较两个对象时比较的是两个对象的内存地址值
对于equals方法,注意:equals方法不能作用于基本数据类型的变量
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容
简单概括就是:
== 在基本数据类型:值内容, 引用类型时:地址
equals 重写:值内容 , equals不重写:地址
equals()方法源码解析
源代码
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
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;
}
`
从源码中知道,equals()方法存在于Object类中,因为Object类是所有类的直接或间接父类,也就是说所有的类中的equals()方法都继承自Object类,而通过源码我们发现,Object类中equals()方法底层依赖的是==,那么,在所有没有重写equals()方法的类中,调用equals()方法其实和使用==的效果一样,也是比较的地址值,然而,Java提供的所有类中,绝大多数类都重写了equals()方法,equals方法进行了重写则是用来比较指向的对象所存储的内容是否相等,当然有兴趣的朋友可以自己自定义一个类【默认是没有重写equals()方法】去试着用equals方法体会体会!
几个例子试着检验一下自己
Integer aaa=new Integer(5);
Integer bbb=new Integer(5);
int a=10;
int b=10;
String str1=new String("justice");
String str2=new String("justice");
String str3;
str3=str1;
System.out.println(aaa==bbb);
System.out.println(aaa.equals(bbb));
System.out.println(a==b);
System.out.println(str1==str2);
System.out.println(str1.equals(str2));
System.out.println(str1==str3);
System.out.println(str1.equals(str3));
结果:
false
true
true
false
true
true
true
分析:
aaa和bbb都是Integer封装类型,是不同的对象,变量存储地址, 所以==结果为false,equals为true
a和b都是基本数据类型,变量存储值,所以==为true,基本数据类型无equals方法
str1和str2都是String类型,属于引用类型,变量存储地址,所以==为false,equals为true
创建str3的时候,str3指向了str1,所以str1和str3的指向同一个地址,存储的数据自然相同,所以均为true
涉及内存中的常量池问题例子
String s1 = "abc";
String s2 = "abc";
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
答案是:true true
为什么第二个会是true呢?这就涉及到了内存中的常量池,常量池属于方法区的一部分,当运行到s1创建对象时,如果常量池中没有,就在常量池中创建一个对象"abc",第二次创建的时候,就直接使用,所以两次创建的对象其实是同一个对象,它们的地址值相等。
既然了解了内存中的常量池,那分析一下下面str1==str2为 false 的原因
String str1 = new String(“abcd”);
String str2 = new String(“abcd”);
str1==str2为 false
分析: 这里创建了两次对象,一次是在常量池中创建了对象"abc",一次是在堆内存中创建了对象str1,所以str1和str2的地址值不相等。
再来一个有意思的例子:
Integer a=100;
Integer b=1000;
Integer c=100;
Integer d=1000;
System.out.println(a==b);
System.out.println(a==c);
System.out.println(b==c);
System.out.println(b==d);
结果为:
false
true
false
false
分析:
大家觉得a和c是不同的对象,所以地址不同,所以结果为false才对,但是定义一个Integer变量时,会默认进行Integer.valueOf(a)操作,方法的源码如下:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
high的值为127,low的值为-128,当进行这个方法时如果值在-128-127之间,返回的值也就是地址是相同的,所以a和c的地址相同,a==c自然为true
总结(好记):
" == "在基本数据类型:值内容, 引用类型时:地址
equals 重写:值内容 , equals不重写:地址