前言
这是一个比较老生常谈的问题了,先说结论:
- equlas默认比较的是地址值。因为Object类是所有类的父类,如果当前类重写了Object的equals方法,则按照重写的规则去处理
==的情况,如果是基本数据类型比较的是真实值,如果是引用数据类型,比较的是地址值
==
Java中定义了八种基本数据类型,依次是byte,short,int,long,boolean,float,double,char;以及引用数据类型,例如String
先看代码
public static void main(String[] args) {
int i = 1;
int j = 1;
String x = new String("hello word");
String y = new String("hello word");
System.out.println(i == j);
System.out.println(x == y);
}
结果分别是true和false;
上述结果证明了,针对==的结论是正确
但在编码过程中,实际申明String的过程如下:
public static void main(String[] args) {
String x = "hello word";
String y = "hello word";
System.out.println(x == y);
}
结果是true
因为在JVM中,申明的字符串是存储在字符串常量池中,当声明y变量时,JVM会发现常量池中已经存在了hello word了,直接引用了该字符串;所以导致了结果是true,但实际上比较的还是地址值
equals
先看Object的equals方法
public boolean equals(Object obj) {
return (this == obj);
}
Object类中的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;
}
String类中先进行了==(引用类型进行地址值比较),如果引用的是同一个字符串,则返回true。否则进行值比较
再看一下Integer类的equals方法
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Integer类中实际采用了值比较(将Integer引用类型转成了int类型)
综述,equals,如果当前类没有重写equals方法,比较的是地址值;如果重写了该方法,则按照重写规则比较
题外话
看如下代码:
public static void main(String[] args) {
Integer i = 1;
Integer j = 1;
Integer x = 129;
Integer y = 129;
System.out.println(i == j);
System.out.println(x == y);
}
上述代码执行的结果是true,flase
根据之前的结论,==在引用数据类型,比较的是地址值;那为什么会造成这种结果?
Java有一种存在叫做自动装箱,通过javap查看字节码可以得到如下内容
在申明Integer i = 1时,执行了Integer.valueOf方法,这就是自动装箱
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer类中配置了一个静态缓存数组(也就是上面的IntegerCache),存储了-127 ~ 128内的数字; 如果在执行valueOf方法时,发现申明的数值在-127 ~ 128范围内,直接返回缓存中的对象 如果不是,则返回一个新的Integer对象。
也就是说,在上面的代码中,==针对Integer依旧比较的是地址值,只是数值在-127~128以内,返回的是Integer类缓存的对象。所以会导致i == j 是true。
这种现象不仅限于Integer类,包括:
| 类型 | 缓存范围 | 说明 |
|---|---|---|
| Byte | -128 到 127 | - |
| Short | -128 到 127 | - |
| Integer | -128 到 127 | - |
| Long | -128 到 127 | - |
| Character | 0 到 127 | ASCII字符 |
| Boolean | true/false | |
| String | 常量池 | 编译时确定的字符串 |