jdk8和11中equals区别比较(String.equals)
实例
test.java
public class test {
public static void main(String[] args) {
String a = "abcde";
System.out.println("a为"+a);
String b = "abcde";
System.out.println("b为"+b);
String c = new String("abcde");
System.out.println("c为"+c);
System.out.println("a==b的结果是:" + (a == b));
System.out.println("a.equals(b)的结果是:" + a.equals(b));
System.out.println("a==b的结果是:" + (a == c));
System.out.println("a.equals(b)的结果是:" + a.equals(c));
}
}
输出
a为abcde
b为abcde
c为abcde
a==b的结果是:true
a.equals(b)的结果是:true
a==b的结果是:false
a.equals(b)的结果是:true
结果为a和b无论"=="还是equals结果都为true,而a和c的"=="为false,equals为true
,下面展开分析
"=="的比较原理
在编译String a=“abcde"的时候其实是jvm在常量池中创建了一个内容为"abcde"的地址值,然后让a去指向"abcde”,而不是把"abcde"直接赋值给a;
在编译String b=“abcde"的时候常量池中已经有了"abcde"的地址值
,所以让b直接指向常量池中的"abcde”,这样a和b的地址值
都是常量池中"abcde"的地址值
,所以通过双等号的运算结果是true。
在执行String c = new String(“abcde”);时,在堆内存中重新开辟了一块空间来存储"abcde",导致a和c的地址不同,所以"=="结果为false
也就是说,"=="比较引用数据类型(String),比较的是内存中的地址,而比较基本数据类型时,比较的是值,不过,由于java中只有值传递,因此==比较的都是值,比较地址时,不过是把地址作为值传递
equals的比较原理(jdk1.8)
这里直接看jdk1.8中equals的源码,非常清晰明了
public boolean equals(Object anObject) {
if (this == anObject) { //this为a,anObject为c,第一步还是使用"=="比较a和c的地址值
return true; //地址不同则往下
}
if (anObject instanceof String) { //判断c是否是String的实例,不是则直接false
String anotherString = (String)anObject; //转型
int n = value.length; //此处省略this,实际n为a的长度
if (n == anotherString.value.length) { //若长度不等直接false
char v1[] = value; //将a转为字符数组
char v2[] = anotherString.value; //将c转为字符数组
int i = 0;
while (n-- != 0) { //for循环,内容不等则直接false
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
简单来说,equals还是走的"“比较地址,不过比”"多了匹配内容的步骤
equals的比较原理(jdk11)
上源码
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
jdk11与jdk8大同小异,不过添加了一些额外的步骤,如第一个是if (coder() == aString.coder())
coder()源码如下:
byte coder() {
return COMPACT_STRINGS ? coder : UTF16;
}
COMPACT_STRINGS
默认值为true,coder
默认值为0,UTF16
默认值为1,因此coder()方法返回值为0
isLatin1()源码如下:
private boolean isLatin1() {
return COMPACT_STRINGS && coder == LATIN1;
}
@Native static final byte LATIN1 = 0;
COMPACT_STRINGS
默认值为true,coder
默认值为0,LATIN1默认值为0,因此isLatin1()返回值为true
StringLatin1.equals(value, aString.value)方法源码如下,和jdk8一模一样就不多解释了
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
总结
从源码分析可见jdk8和jdk11中对于equals的代码没有本质变动,都是先使用"=="比较其地址值,然后再比较其属性