==
对于基本数据类型来说,主要是匹配值是否相同。
public class Equals {
public static void main(String[] args) {
int a = 1;
int b = 1;
System.out.println(a == b);
System.out.println(b == a);
}
}
复制代码
输出结果如下:
true
true
复制代码
对于引用类型来说,==匹配的是两个是否指向了同一内存区域。
public class Equals {
static Person person1 = new Person();
static Person person2 = new Person();
public static void main(String[] args) {
System.out.println(person1 == person2);
}
}
复制代码
上述通过new关键字分别创建了2个对象,此时我们用==进行比较,结果如下
false
复制代码
这里涉及到对象创建的只是了,后续在虚拟机相关笔记中体现。
equal
equals
是 Java 中所有对象的父类,即 Object
类定义的一个方法。它只能比较对象,它表示的是引用双方的值是否相等。
public class Equals {
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = new Person();
person1.setName("1");
person2.setName("1");
System.out.println(person1.getName().equals(person2.getName()));
}
}
复制代码
equals 用作对象之间的比较具有如下特性
自反性
:对于任何非空引用 x 来说,x.equals(x) 应该返回 true。对称性
:对于任何非空引用 x 和 y 来说,若x.equals(y)为 true,则y.equals(x)也为 true。传递性
:对于任何非空引用的值来说,有三个值,x、y 和 z,如果x.equals(y) 返回true,y.equals(z) 返回true,那么x.equals(z) 也应该返回true。一致性
:对于任何非空引用 x 和 y 来说,如果 x.equals(y) 相等的话,那么它们必须始终相等。非空性
:对于任何非空引用的值 x 来说,x.equals(null) 必须返回 false。
String的equal实现
String也是在日常编程中经常使用的修饰符之一,它和其它基本数据类型不同,String本身是一个常量(final),其不能被其他对象所继承(至于原因,据说是开发者觉得String实现已经非常完美了,不想开发者任意扩展来破坏它),其一经赋值便无法再改变,继承自Object,所以Object具有的能力在String中都可以找到相对于的。
此处我们重点分析,String中的equal实现。
public boolean equals(Object anObject) {
// 首先满足自反性,自己传入自己确保返回为true
if (this == anObject) {
return true;
}
// 确保传入的Object为String类型
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
// 判断长度是否相等,如果不等一定为false
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 开始逐个字符比较,如果发现不相等的字符,则返回false
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
复制代码
String中equals的实现总结来说可以是以下几点:
1.判断是否传入的是自身,如果是返回true。
2.判断是否是String对象,如果不是返回true。
2.1 如果是String对象 则比较传入的len是否一致,如果一致,则继续比较。
2.2 比较字符,如果字符不一致,则返回false,反之继续比较直到比较完全(这里是一个循环全量匹配)
这里再提示一下,你可能有疑惑什么时候是
if (this == anObject) {
return true;
}
复制代码
这个判断语句如何才能返回 true?因为都是字符串啊,字符串比较的不都是堆空间吗,猛然一看发现好像永远也不会走,但是你忘记了 String.intern()
方法,它表示的概念在不同的 JDK 版本有不同的区分
在 JDK1.7 及以后调用 intern 方法是判断运行时常量池中是否有指定的字符串,如果没有的话,就把字符串的引用添加到常量池中,并不是复制一份对象放入其中了。
重写HashCode
equals 方法和 hashCode 都是 Object 中定义的方法,它们经常被一起重写。
equals 方法是用来比较对象大小是否相等的方法,hashcode 方法是用来判断每个对象 hash 值的一种方法。如果只重写 equals 方法而不重写 hashcode 方法,很可能会造成两个不同的对象,它们的 hashcode 也相等,造成冲突。比如
String str1 = "通话";
String str2 = "重地";
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
复制代码
上述两个字符串所代表的hashcode就是相同的。
1179395
1179395
复制代码
它们两个的 hashcode 相等,但是 equals 可不相等。
关于equals总结如下
- 如果在 Java 运行期间对同一个对象调用 hashCode 方法后,无论调用多少次,都应该返回相同的 hashCode,但是在不同的 Java 程序中,执行 hashCode 方法返回的值可能不一致。
- 如果两个对象的 equals 相等,那么 hashCode 必须相同
- 如果两个对象 equals 不相等,那么 hashCode 也有可能相同,所以需要重写 hashCode 方法,因为你不知道 hashCode 的底层构造(后续可以解析jvm源码深入认识hashcode的构造),所以你需要重写 hashCode 方法,来为不同的对象生成不同的 hashCode 值,这样能够提高不同对象的访问速度。
- hashCode 通常是将地址转换为整数来实现的。