一 概念简介
1 ==和equals比较运算符:==要求两个引用变量指向同一对象时才返回true,equals方法则允许用户提供自定义的相等规则。
2 object类提供的equals方法判断两个对象相等的标准与==完全相同。因此开发者通常需要重写equals方法。
二 ==号比较应用
1 代码示例
public class EqualTest { public static void main(String[] args) { int it = 65; float fl = 65.0f; // 将输出true System.out.println("65和65.0f是否相等?" + (it == fl)); char ch = 'A'; // 将输出true System.out.println("65和'A'是否相等?" + (it == ch)); String str1 = new String("hello"); String str2 = new String("hello"); // 将输出false System.out.println("str1和str2是否相等?" + (str1 == str2)); // 将输出true System.out.println("str1是否equals str2?" + (str1.equals(str2))); // 由于java.lang.String与EqualTest类没有继承关系, // 所以下面语句导致编译错误 // System.out.println("hello" == new EqualTest()); } }
2 运行结果
65和65.0f是否相等?true
65和'A'是否相等?true
str1和str2是否相等?false
str1是否equals str2?true
3 结果分析
如果两个变量是基本类型变量,且都是数值类型(不一定要求数据类型严格相同),则只要两个变量的值相等,就将返回true。
如果是两个引用类型变量,只有它们指向对一对象时,==判断才会返回true。
三 字符串的==号比较
1 代码示例
public class StringCompareTest { public static void main(String[] args) { // s1直接引用常量池中的"黑客攻击" String s1 = "黑客攻击"; String s2 = "黑客"; String s3 = "攻击"; // s4后面的字符串值可以在编译时就确定下来 // s4直接引用常量池中的"黑客攻击" String s4 = "黑客" + "攻击"; // s5后面的字符串值可以在编译时就确定下来 // s5直接引用常量池中的"黑客攻击" String s5 = "黑" + "客" + "攻击"; // s6后面的字符串值不能在编译时就确定下来, // 不能引用常量池中的字符串 String s6 = s2 + s3; // 使用new调用构造器将会创建一个新的String对象, // s7引用堆内存中新创建的String对象 String s7 = new String("黑客攻击"); System.out.println(s1 == s4); // 输出true System.out.println(s1 == s5); // 输出true System.out.println(s1 == s6); // 输出false System.out.println(s1 == s7); // 输出false } }
2 运行结果
true
true
false
false
3 结果分析
JVM常量池保证相同的字符串直接量只有一个,不会产生多个副本,例子中s1,s4,s5所引用的字符串可以在编译期确定下来,因此它们都引用常量池中的同一字符串对象。
使用new String()创建的字符串是在运行时创建出来的,它保存在运行时内存区,不会放入常量池中。
四 equals方法错误应用
1 代码示例
class Person { // 重写equals()方法,提供自定义的相等标准 public boolean equals(Object obj) { // 不加判断,总是返回true,即Person对象与任何对象都相等 return true; } } // 定义一个Dog空类 class Dog{} public class OverrideEqualsError { public static void main(String[] args) { Person p = new Person(); System.out.println("Person对象是否equals Dog对象?" + p.equals(new Dog())); System.out.println("Person对象是否equals String对象?" + p.equals(new String("Hello"))); } }
2 运行结果
Person对象是否equals Dog对象?true
Person对象是否equals String对象?true
3 结果分析
造成这种荒唐结果的原困是重写Person类的equaIs方法时没有任何判断,无条件返回true。
五 equals方法正确应用
1 代码示例
class Person { private String name; private String idStr; public Person(){} public Person(String name , String idStr) { this.name = name; this.idStr = idStr; } // 此处省略name和idStr的setter和getter方法。 // name的setter和getter方法 public void setName(String name) { this.name = name; } public String getName() { return this.name; } // idStr的setter和getter方法 public void setIdStr(String idStr) { this.idStr = idStr; } public String getIdStr() { return this.idStr; } // 重写equals()方法,提供自定义的相等标准 public boolean equals(Object obj) { // 如果两个对象为同一个对象 if (this == obj) return true; // 只有当obj是Person对象 if (obj != null && obj.getClass() == Person.class) { Person personObj = (Person)obj; // 并且当前对象的idStr与obj对象的idStr相等才可判断两个对象相等 if (this.getIdStr().equals(personObj.getIdStr())) { return true; } } return false; } } public class OverrideEqualsRight { public static void main(String[] args) { Person p1 = new Person("孙猴子" , "12343433433"); Person p2 = new Person("孙行者" , "12343433433"); Person p3 = new Person("局八戒" , "99933433"); // p1和p2的idStr相等,所以输出true System.out.println("p1和p2是否相等?" + p1.equals(p2)); // p2和p3的idStr不相等,所以输出false System.out.println("p2和p3是否相等?" + p2.equals(p3)); } }
2 运行结果
p1和p2是否相等?true
p2和p3是否相等?false
3 结果分析
通常而言,正确重写equals方法应满足:自反性,对称性,传递性,一致性,对于任何不是null的x,x.equals(null)一定返回faIse。