ホームページ  >  記事  >  Java  >  Java でオブジェクトが等しいかどうかを判断するために、equals() メソッドを使用する方法に関するチュートリアル

Java でオブジェクトが等しいかどうかを判断するために、equals() メソッドを使用する方法に関するチュートリアル

高洛峰
高洛峰オリジナル
2017-02-03 13:08:573000ブラウズ

Objectクラスのequalsメソッドは、あるオブジェクトが別のオブジェクトと等しいかどうかを検出するために使用されます。 Object クラスでは、このメソッドは 2 つのオブジェクトが同じ参照を持つかどうかを判断します。2 つのオブジェクトが同じ参照を持つ場合、それらは等しい必要があります。この観点から、これをデフォルトのアクションにするのは理にかなっています。ただし、ほとんどのクラスでは、この判断は意味がありません。たとえば、この方法で 2 つの PrintStream を比較することはまったく意味がありません。ただし、多くの場合、2 つのオブジェクトの状態が等しいことを検出する必要があります。2 つのオブジェクトの状態が等しい場合、2 つのオブジェクトは等しいと見なされます。したがって、カスタム クラスでは等しい比較をオーバーライドする必要があります。

以下は、完璧なequals()メソッドを書くための提案です:

(1) 明示的なパラメータにotherObjectという名前を付けます。これは後でotherという変数に変換する必要があります

(2) thisとotherObjectが同じかどうかを確認します参照オブジェクト:

if(this==otherObject) return true;

このステートメントは単なる最適化です。実際、これはよく取られる形です。この方程式の計算は、クラス内のフィールドを 1 つずつ比較するよりもはるかに低コストであるためです。

(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 を使用します。

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;
}

Deeper
以下は、「クラスがequals()メソッドをカバーするかどうか」に応じて2つのカテゴリに分類されます。
(1) クラスがquals() メソッドをカバーしていない場合、equals() を通じて 2 つのオブジェクトを比較するとき、実際には 2 つのオブジェクトが同じオブジェクトであるかどうかが比較されます。このとき、2つのオブジェクトを「==」で比較することと同じになります。
(2) クラスのequals()メソッドをオーバーライドして、他のメソッドを通じて2つのオブジェクトが等しいかどうかをequals()に比較させることができます。通常のアプローチは次のとおりです。2 つのオブジェクトの内容が等しい場合、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

結果分析
「比較」には p1.equals(p2) を使用します。 p1 と p2 が等しいとき」。実際には、Object.javaのequals()メソッドが呼び出されます、つまり、(p1==p2)が呼び出されます。 「p1とp2が同じオブジェクトかどうか」を比較します。
p1 と p2 の定義から、それらは同じ内容を持っていますが、2 つの異なるオブジェクトであることがわかります。したがって、戻り結果は false になります。

2.「equals()メソッドをオーバーライドする」場合

上記のEqualsTest1.javaを修正して、equals()メソッドをオーバーライドします。
コードは次のとおりです(EqualsTest2.java):

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;
  }
 }
}

実行結果:

true

結果分析:

EqualsTest2.javaの人物のequals()関数を書き換えました: 2人の人物の名前と年齢がオブジェクトが両方とも等しい場合、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() の役割を確認してみましょう。2 つのオブジェクトが等しいかどうかを判断します。 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 までご連絡ください。