==和equals方法
Java程序中测试两个变量时否相等有两种方法: == 和 equals。
==判断
当使用==来判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数字类型(不一定要求数据类型严格相同),则只要两个变量的值相同,就将返回true。
但对于两个引用类型变量,只有它们指向同一个对象时,== 判断才会返回true。
== 不可用于比较类型上没有父子关系的两个变量。
public static void main(String[] args) { int i = 65; float f = 65.0f; // 输出true System.out.println("65和65.0f是否相等?" + (i == f)); char c = 'A'; // 输出true System.out.println("65和'A'是否相等?" + (i == c)); String s1 = new String("Test"); String s2 = new String("Test"); // 输出false System.out.println("s1和s2是否相等?" + (s1 == s2)); // 输出true System.out.println("s1和s2是否相等?" + (s1.equals(s2))); // 编译不过 // System.out.println("Test" == new EqualTest()); }
需要注意 "Test"和new String("Test")是有区别的?
“Test”是字符串直接量(即可以在编译时就计算出来的字符串值),JVM使用常量池来管理这些字符串,
当使用new String("Test")时,JVM先使用常量池来管理“Test”直接量,再调用String类的构造器来创建一个新的String对象,新创建的String对象被保存在堆内存中。也就是说new String("Test")一共创建了两个字符串对象。
常量池(constant pool)专门用来管理在编译时被确定并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口中的常量,还包括字符串常量。
public static void main(String[] args) { String s1 = "Hello"; String s2 = "H"; String s3 = "ello"; // 不能在编译时确定 String s4 = s2 + s3; // 在编译时就确定下来了,直接引用常量池中的“Hello” String s5 = "H" + "ello"; // 引用内存中新创建的String对象 String s6 = new String("Hello"); // true System.out.println(s1 == s5); // false System.out.println(s1 == s4); // false System.out.println(s1 == s6); }
equals判断
equals()方法是Object类提供的一个实例方法,因此所有的引用变量都可以调用该方法来判断是否与其他引用变量相等。
判断两个对象相等时,和==运算符没有区别,同样要求两个引用变量指向同一个对象才返回true。因此Object提供的equals方法没有太大的意义,可以重写equals()方法实现。
注意,String已经重写了equals()方法,只要两个字符串所包含的字符串序列相同,则返回true。
笼统的说equals()方法是判断两个对象的值相等,这样的说法并不准确。
public class EqualsTest { public static void main(String[] args) { Person p1 = new Person("小王", "1234"); Person p2 = new Person("王二", "1234"); Person p3 = new Person("小王", "12345"); // true System.out.println(p1.equals(p2)); // false System.out.println(p1.equals(p3)); } } class Person { private String name; private String idStr; public Person() { } public Person(String name, String idStr) { this.name = name; this.idStr = idStr; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getIdStr() { return idStr; } public void setIdStr(String idStr) { this.idStr = 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; } }
正确的重写equals()方法,应该满足下列条件:
1. 自反性:对任意的x,x.equals(x)一定返回true。
2. 对称性:对任意x, y,如果x.equals(y)返回true,则y.equals(x)返回true。
3. 传递性:对任意x, y, z,如果x.equals(y)返回true,y.equals(x)返回true,则x.equals(z)也返回true。
4. 一致性:对任意x, y,如果对象中用于等价比较的信息没有改变,那么无论x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,一直是false。
5. 对任何不是null的x, x.equals(null)一定返回false。
Object默认提供的equals()只是比较对象的地址,即Object类的equals()方法比较的结果与==运算符比较的结果完全相同。因此,在实际应用中常常需要重写equals()方法,相等的条件是由业务要求决定,因此equals()方法的实现也是由业务要求决定。