首頁  >  文章  >  Java  >  Java中判斷物件是否相等的equals()方法使用教程

Java中判斷物件是否相等的equals()方法使用教程

高洛峰
高洛峰原創
2017-02-03 13:08:573047瀏覽

Object類別中的equals方法用來偵測一個物件是否等於另一個物件。在Object類別中,這個方法判斷兩個物件是否有相同的引用,如果兩個物件有相同的引用,它們一定是相等的。從這點上看,將其作為預設操作也是合乎情理的。然而,對於多數類類說,這種判斷並沒有什麼意義,例如,採用這種方式比較兩個PrintStream是否相等就完全沒有意義。然而,經常需要偵測兩個物件狀態的相等性,如果兩個物件的狀態相等,就認為這兩個物件是相等的。所以一般在自訂類別都要重寫equals比較。

下面給出編寫一個完美equals()方法的建議:

(1)明確參數命名為otherObject,稍後需要將轉換成一個叫other的變數

(2)偵測this與otherObject是否引用同一個物件:

if(this==otherObject) return true;

這條語句只是一個最佳化。實際上,這是一種經常採用的形式。因為計算這個等式要比一個一個比較類中的域所付出的代價小的多。

(3)偵測otherObject是否為null,如果為null,回傳false。這項檢測是很有必要的。

if(otherObject==null) return false;

(4)比較this和otherObject是否屬於同一類,如果equals的語義在每個子類中有所改變,就使用getClass()檢測,它將自己作為目標類

if(getClass()!=otherObject.getClass()) return false;

如果所有的子類別都擁有相同的語義,就使用instanceof檢測

if(!(otherObject instanceof ClassName)) return false;

(5)將otherObject轉換為相應類型的變數:

ClassName other=(ClassName)otherObject;

(6)現在開始對所有需要比較的領域進行比較。使用==比較基本型域,使用equals比較物件域。如果所有網域都匹配,就回傳true,否則回傳false;

return field1==other.field1&&field2.equals(other.field2)

如果在子類別中重新定義equals,就要在其中包含呼叫super.equals(other)。如果偵測失敗,就不可能相等。如果超類別中的域相等,就比較子類別中的實例域。

對於陣列類型的域,可以使用靜態的Arrays.equals方法來偵測對應的元素是否相等。

來看幾個字串比較例子:

String a = "abc";
String b = "abc";
String c = new String("abc");
String d = new String("abc");
System.out.println(a == b); // true 因为JAVA中字符串常量是共享的,只有一个拷贝
System.out.println(a == c); // false a和c属于2个不同的对象
System.out.println(a.equals(c)); // true 由于String对象的equals方法比较的是对象中的值,所以返回true。(和Object的equals方法不同)
System.out.println(c==d); // false c和d虽然对象内的值相同,但属于2个不同的对象,所以不相等
System.out.println(c.equals(d)); // true

簡單的說,當比較字串常數時,等於和equals傳回的結果一樣,當想比較字串物件的值時用equals。

看一個equals的使用例子:

package chapter05.EqualsTest;
  
import java.util.*;
  
public class EqualsTest {
 public static void main(String[] args) {
  Employee alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15);
  Employee alice2 = alice1; // reference the same object
  Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15);
  Employee bob = new Employee("Bob Brandson", 50000, 1989, 10, 1);
  
  System.out.println("alice1 == alice2: " + (alice1 == alice2));
  
  System.out.println("alice1 == alice3: " + (alice1 == alice3));
  
  System.out.println("alice1.equals(alice3): " + (alice1.equals(alice3)));
  
  System.out.println("alice1.equals(bob): " + (alice1.equals(bob)));
  
  System.out.println(bob.toString());
 }
}
  
class Employee {
 public Employee(String n, double s, int year, int month, int day) {
  name = n;
  salary = s;
  GregorianCalendar calendar = new GregorianCalendar(year, month, day);
  hireDay = calendar.getTime();
 }
  
 public String getName() {
  return name;
 }
  
 public double getSalary() {
  return salary;
 }
  
 public Date getHireDay() {
  return hireDay;
 }
  
 public void raiseSalary(double byPercent) {
  double raise = salary * byPercent / 100;
  salary += raise;
 }
  
 @Override
 public boolean equals(Object otherObject) {
  // a quick test to see if the objects are identical
  if (this == otherObject)
   return true;
  
  // must return false if the explicit parameter is null
  if (otherObject == null)
   return false;
  
  // if the classed don't match,they can't be equal
  if (getClass() != otherObject.getClass())
   return false;
  
  // now we know otherObject is a non-null Employee
  Employee other = (Employee) otherObject;
  
  // test whether the fields hava identical values
  return name.equals(other.name) && salary == other.salary
    && hireDay.equals(other.hireDay);
  
 }
  
 @Override
 public int hashCode() {
  return 7 * name.hashCode() + 11 * new Double(salary).hashCode() + 13
    * hireDay.hashCode();
 }
  
 @Override
 public String toString() {
  return getClass().getName() + "[name=" + name + ",salary=" + salary
    + ",hireDay=" + hireDay + "]";
 }
  
 private String name;
 private double salary;
 private Date hireDay;
}
  
class Manager extends Employee {
 public Manager(String n, double s, int year, int month, int day) {
  super(n, s, year, month, day);
  bouns = 0;
 }
  
 @Override
 public double getSalary() {
  double baseSalary = super.getSalary();
  return baseSalary + bouns;
 }
  
 public void setBouns(double b) {
  bouns = b;
 }
  
 @Override
 public boolean equals(Object otherObject) {
  if (!super.equals(otherObject))
   return false;
  Manager other = (Manager) otherObject;
  // super equals checked that this and other belong to the same class
  return bouns == other.bouns;
 }
  
 @Override
 public int hashCode() {
  return super.hashCode() + 17 * new Double(bouns).hashCode();
 }
  
 @Override
 public String toString() {
  return super.toString() + "[bouns=" + bouns + "]";
 }
  
 private double bouns;
}

深入
下面根據“類別是否覆蓋equals()方法”,將它分為2類。
(1) 若某個類別沒有覆寫equals()方法,當它的透過equals()比較兩個物件時,實際上是比較兩個物件是不是同一個物件。這時,等價於透過「==」去比較這兩個物件。
(2) 我們可以覆寫類別的equals()方法,來讓equals()透過其它方式比較兩個物件是否相等。通常的做法是:若兩個物件的內容相等,則equals()方法傳回true;否則,傳回fasle。
下面,舉例對上面的2種情況進行說明。
1. 「沒有覆寫equals()方法」的情況
程式碼如下(EqualsTest1.java):

import java.util.*;
import java.lang.Comparable;
 
/**
 * @desc equals()的测试程序。
 
 */
public class EqualsTest1{
 
 public static void main(String[] args) {
  // 新建2个相同内容的Person对象,
  // 再用equals比较它们是否相等
  Person p1 = new Person("eee", 100);
  Person p2 = new Person("eee", 100);
  System.out.printf("%s\n", p1.equals(p2));
 }
 
 /**
  * @desc Person类。
  */
 private static class Person {
  int age;
  String name;
 
  public Person(String name, int age) {
   this.name = name;
   this.age = age;
  }
 
  public String toString() {
   return name + " - " +age;
  }
 }
}

運行結果:

false


結果分析
我們透過運行結果:

import java.util.*;
import java.lang.Comparable;
 
/**
 * @desc equals()的测试程序。
 */
public class EqualsTest2{
 
 public static void main(String[] args) {
  // 新建2个相同内容的Person对象,
  // 再用equals比较它们是否相等
  Person p1 = new Person("eee", 100);
  Person p2 = new Person("eee", 100);
  System.out.printf("%s\n", p1.equals(p2));
 }
 
 /**
  * @desc Person类。
  */
 private static class Person {
  int age;
  String name;
 
  public Person(String name, int age) {
   this.name = name;
   this.age = age;
  }
 
  public String toString() {
   return name + " - " +age;
  }
 
  /**
   * @desc 覆盖equals方法
   */
  @Override
  public boolean equals(Object obj){
   if(obj == null){
    return false;
   }
 
   //如果是同一个对象返回true,反之返回false
   if(this == obj){
    return true;
   }
 
   //判断是否类型相同
   if(this.getClass() != obj.getClass()){
    return false;
   }
 
   Person person = (Person)obj;
   return name.equals(person.name) && age==person.age;
  }
 }
}

結果分析
我們透過1.equals1. p2是否相等時」。實際上,所呼叫的Object.java的equals()方法,即所呼叫的 (p1==p2) 。它是比較「p1和p2是否是同一個物件」。
而由 p1 和 p2 的定義可知,它們雖然內容相同;但它們是兩個不同的物件!因此,返回結果是false。

2. "覆寫equals()方法"的情況

我們修改上面的EqualsTest1.java:覆寫equals()方法。

程式碼如下(EqualsTest2.java):

true



運行結果:

import java.util.*;
import java.lang.Comparable;
 
/**
 * @desc equals()的测试程序。
 */
public class EqualsTest3{
 
 public static void main(String[] args) {
  // 新建2个相同内容的Person对象,
  // 再用equals比较它们是否相等
  Person p1 = new Person("eee", 100);
  Person p2 = new Person("eee", 100);
  System.out.printf("p1.equals(p2) : %s\n", p1.equals(p2));
  System.out.printf("p1==p2 : %s\n", p1==p2);
 }
 
 /**
  * @desc Person类。
  */
 private static class Person {
  int age;
  String name;
 
  public Person(String name, int age) {
   this.name = name;
   this.age = age;
  }
 
  public String toString() {
   return name + " - " +age;
  }
 
  /**
   * @desc 覆盖equals方法
   */
  @Override
  public boolean equals(Object obj){
   if(obj == null){
    return false;
   }
 
   //如果是同一个对象返回true,反之返回false
   if(this == obj){
    return true;
   }
 
   //判断是否类型相同
   if(this.getClass() != obj.getClass()){
    return false;
   }
 
   Person person = (Person)obj;
   return name.equals(person.name) && age==person.age;
  }
 }
}

結果分析:
我們在EqualsTest2.java 中重寫了Person的equals()函數:當函數:當我們在EqualsTest2.java 中重寫了Person的equals():當函數:當我們在EqualsTest2.java 中都相等,則傳回true。
因此,運行結果回傳true。
講到這裡,順便說一下java對equals()的要求。有以下幾點:
對稱性:如果x.equals(y)回傳是"true",那麼y.equals(x)也應該回傳是"true"。
反射性:x.equals(x)必須回傳是"true"。

類別推性:如果x.equals(y)回傳是"true",而且y.equals(z)回傳是"true",那麼z.equals(x)也應該回傳是"true"。

一致性:如果x.equals(y)回傳是"true",只要x和y內容一直不變,不管你重複x.equals(y)多少次,回傳都是"true"。
非空性,x.equals(null),永遠回傳是"false";x.​​equals(和x不同類型的物件)永遠回傳是"false"。

現在,再回顧一下equals()的作用:判斷兩個物件是否相等。當我們重寫equals()的時候,可千萬不好將它的作用給改變了! 🎜🎜🎜🎜

equals() 与 == 的区别是什么?
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况(前面第1部分已详细介绍过):
     情况1,类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。
     情况2,类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。
下面,通过示例比较它们的区别。
代码如下:

import java.util.*;
import java.lang.Comparable;
 
/**
 * @desc equals()的测试程序。
 */
public class EqualsTest3{
 
 public static void main(String[] args) {
  // 新建2个相同内容的Person对象,
  // 再用equals比较它们是否相等
  Person p1 = new Person("eee", 100);
  Person p2 = new Person("eee", 100);
  System.out.printf("p1.equals(p2) : %s\n", p1.equals(p2));
  System.out.printf("p1==p2 : %s\n", p1==p2);
 }
 
 /**
  * @desc Person类。
  */
 private static class Person {
  int age;
  String name;
 
  public Person(String name, int age) {
   this.name = name;
   this.age = age;
  }
 
  public String toString() {
   return name + " - " +age;
  }
 
  /**
   * @desc 覆盖equals方法
   */
  @Override
  public boolean equals(Object obj){
   if(obj == null){
    return false;
   }
 
   //如果是同一个对象返回true,反之返回false
   if(this == obj){
    return true;
   }
 
   //判断是否类型相同
   if(this.getClass() != obj.getClass()){
    return false;
   }
 
   Person person = (Person)obj;
   return name.equals(person.name) && age==person.age;
  }
 }
}

运行结果:

p1.equals(p2) : true
p1==p2 : false

结果分析:
在EqualsTest3.java 中:
(1) p1.equals(p2)
这是判断p1和p2的内容是否相等。因为Person覆盖equals()方法,而这个equals()是用来判断p1和p2的内容是否相等,恰恰p1和p2的内容又相等;因此,返回true。
(2) p1==p2
这是判断p1和p2是否是同一个对象。由于它们是各自新建的两个Person对象;因此,返回false。

更多Java中判断对象是否相等的equals()方法使用教程相关文章请关注PHP中文网!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn