Javaでequalsメソッドをオーバーライドしようとしています。基本的に2つのデータフィールドPeople
およびname
を持つクラスage
があります。ここで、equals
メソッドをオーバーライドして、2つのPeopleオブジェクト間で確認できるようにします。
私のコードは次のとおりです
public boolean equals(People other){
boolean result;
if((other == null) || (getClass() != other.getClass())){
result = false;
} // end if
else{
People otherPeople = (People)other;
result = name.equals(other.name) && age.equals(other.age);
} // end else
return result;
} // end equals
しかし、age.equals(other.age)
を記述すると、equalsメソッドはStringのみを比較でき、ageはIntegerであるため、エラーが発生します。
提案されているように==
演算子を使用して、問題を解決しました。
//Written by K@stackoverflow
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person("Subash Adhikari", 28));
people.add(new Person("K", 28));
people.add(new Person("StackOverflow", 4));
people.add(new Person("Subash Adhikari", 28));
for (int i = 0; i < people.size() - 1; i++) {
for (int y = i + 1; y <= people.size() - 1; y++) {
boolean check = people.get(i).equals(people.get(y));
System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
System.out.println(check);
}
}
}
}
//written by K@stackoverflow
public class Person {
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!Person.class.isAssignableFrom(obj.getClass())) {
return false;
}
final Person other = (Person) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if (this.age != other.age) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 53 * hash + this.age;
return hash;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
出力:
実行:
-Subash Adhikari-VS-K false
-Subash Adhikari-VS-StackOverflow false
-Subash Adhikari-VS-Subash Adhikari true
-K-VS-StackOverflow false
-K-VS-Subash Adhikari false
-StackOverflow-VS-Subash Adhikari false
-ビルド成功(合計時間:0秒)
まず第一に、あなたはオーバーライドequals
ではなく、オーバーロードそれです。
age
の実際の宣言がなければ、なぜエラーが発生しているのかを説明するのは困難です。
コード全体を投稿していないので詳細はわかりませんが、次のとおりです。
hashCode()
もオーバーライドすることを忘れないでくださいequals
メソッドには、引数タイプとしてObject
ではなくPeople
が必要です。現時点では、equalsメソッドをオーバーライドするのではなく、オーバーロードしています。これは、おそらく後でタイプを確認することを考えると、おそらく望んでいないものです。instanceof
を使用して、それがPeopleオブジェクトであることを確認できます。 if (!(other instanceof People)) { result = false;}
equals
はすべてのオブジェクトに使用されますが、プリミティブには使用されません。年齢はint
(プリミティブ)であり、その場合は==
を使用するだけだと思います。整数(大文字の「I」)は、等しいと比較する必要があるオブジェクトであることに注意してください。詳細については、 JavaでequalsとhashCodeをオーバーライドするときに考慮すべき問題は何ですか? を参照してください。
@Override
public boolean equals(Object that){
if(this == that) return true;//if both of them points the same address in memory
if(!(that instanceof People)) return false; // if "that" is not a People or a childclass
People thatPeople = (People)that; // than we can cast it to People safely
return this.name.equals(thatPeople.name) && this.age == thatPeople.age;// if they have the same name and same age, then the 2 objects are equal unless they're pointing to different memory adresses
}
Effective Javaによる 、
equals
メソッドのオーバーライドは簡単に思えますが、それを間違える多くの方法があり、結果は悲惨な場合があります。問題を回避する最も簡単な方法は、equals
メソッドをオーバーライドしないことです。この場合、クラスの各インスタンスはそれ自体にのみ等しくなります。これは、次の条件のいずれかが当てはまる場合に正しいことです。
クラスの各インスタンスは本質的に一意です。これは、値ではなくアクティブなエンティティを表すThreadなどのクラスに当てはまります。 Objectが提供するequals実装は、これらのクラスに対して正確な動作をします。
クラスが「論理的同等性」テストを提供する必要はありません。たとえば、Java.util.regex.Patternがチェックするために同等の値をオーバーライドできます2つのPatternインスタンスがまったく同じ正規表現を表していたが、設計者はクライアントがこの機能を必要とする、または欲するとは思わなかったかどうか。このような状況では、Objectから継承されたequals実装が理想的です。
スーパークラスはすでに同等の値をオーバーライドしています。スーパークラスの動作はこのクラスに適しています。たとえば、ほとんどのSet実装は、AbstractSetからequals実装を、AbstractListからList実装を、AbstractMapからMap実装を継承します。
クラスはprivateまたはpackage-privateであり、そのequalsメソッドは決して呼び出されないことが確実です。非常にリスクを回避する場合は、equalsメソッドをオーバーライドして、誤って呼び出されないようにすることができます。
equals
メソッドは、同値関係を実装します。次のプロパティがあります。再帰的:null以外の参照値x
の場合、x.equals(x)
はtrueを返す必要があります。
対称:NULL以外の参照値x
およびy
の場合、x.equals(y)
は、y.equals(x)がtrueを返す場合にのみtrueを返す必要があります。
推移的:NULL以外の参照値x
、y
、z
の場合、x.equals(y)
がtrue
を返し、y.equals(z)
がtrue
を返す場合、x.equals(z)
はtrue
を返す必要があります。
一貫性:null以外の参照値x
およびy
の場合、x.equals(y)
の複数の呼び出しは、一貫してtrue
を返すか、等しい比較で使用される情報が変更されない限り、一貫してfalse
を返す必要があります。
Null以外の参照値x
の場合、x.equals(null)
はfalse
を返す必要があります。
==
演算子を使用して、引数がこのオブジェクトへの参照であるかどうかを確認します。その場合、trueを返します。これはパフォーマンスの最適化にすぎませんが、比較に費用がかかる可能性がある場合は実行する価値があります。
instanceof
演算子を使用して、引数のタイプが正しいかどうかを確認します。そうでない場合は、falseを返します。通常、正しい型はメソッドが発生するクラスです。場合によっては、このクラスによって実装されるインターフェイスがあります。クラスが等号コントラクトを改良するインターフェースを実装する場合は、インターフェースを使用して、インターフェースを実装するクラス間で比較を許可します。 Set、List、Map、Map.Entryなどのコレクションインターフェイスには、このプロパティがあります。
引数を正しい型にキャストしてください。このキャストにはinstanceofテストが先行しているため、成功することが保証されています。
クラスの各「重要な」フィールドについて、引数のそのフィールドがこのオブジェクトの対応するフィールドと一致するかどうかを確認します。これらのテストがすべて成功したら、trueを返します。それ以外の場合は、falseを返します。ステップ2のタイプがインターフェースの場合、インターフェースメソッドを介して引数のフィールドにアクセスする必要があります。タイプがクラスの場合、アクセシビリティに応じてフィールドに直接アクセスできる場合があります。
タイプがfloat
またはdouble
ではないプリミティブフィールドの場合は、比較に==
演算子を使用します。オブジェクト参照フィールドの場合、equals
メソッドを再帰的に呼び出します。 float
フィールドには、静的なFloat.compare(float, float)
メソッドを使用します。 double
フィールドには、Double.compare(double, double)
を使用します。 Float.NaN
、-0.0f
および類似のdouble値の存在により、floatおよびdoubleフィールドの特別な処理が必要になります。 float
フィールドとdouble
フィールドを静的メソッドFloat.equals
およびDouble.equals
と比較できますが、これはすべての比較でオートボクシングを必要とし、パフォーマンスが低下します。 array
フィールドについては、これらのガイドラインを各要素に適用します。配列フィールドのすべての要素が重要な場合は、Arrays.equals
メソッドのいずれかを使用します。
一部のオブジェクト参照フィールドには、合法的にnull
が含まれる場合があります。 NullPointerException
の可能性を回避するには、静的メソッドObjects.equals(Object, Object)
を使用して、そのようなフィールドが等しいかどうかを確認します。
// Class with a typical equals method
public final class PhoneNumber {
private final short areaCode, prefix, lineNum;
public PhoneNumber(int areaCode, int prefix, int lineNum) {
this.areaCode = rangeCheck(areaCode, 999, "area code");
this.prefix = rangeCheck(prefix, 999, "prefix");
this.lineNum = rangeCheck(lineNum, 9999, "line num");
}
private static short rangeCheck(int val, int max, String arg) {
if (val < 0 || val > max)
throw new IllegalArgumentException(arg + ": " + val);
return (short) val;
}
@Override public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber)o;
return pn.lineNum == lineNum && pn.prefix == prefix
&& pn.areaCode == areaCode;
}
... // Remainder omitted
}
age
はint
型であると推測しているため、
public boolean equals(Object other){
boolean result;
if((other == null) || (getClass() != other.getClass())){
result = false;
} // end if
else{
People otherPeople = (People)other;
result = name.equals(otherPeople.name) && age == otherPeople.age;
} // end else
return result;
} // end equals
Javaでオブジェクトを比較する場合、セマンティックチェックを作成し、オブジェクトのタイプと識別状態を比較します。
null
ルール:
a.equals(b) == b.equals(a)
equals()
は常にtrue
またはfalse
を生成しますが、NullpointerException
、ClassCastException
またはその他のスロー可能オブジェクトを生成することはありません比較:
instanceof
を型比較に使用する場合、これは正しく実装されないことがよくあります(サブクラスが存在しない場合にのみ機能し、A extends B -> a instanceof b != b instanceof a)
の場合は対称性規則に違反します)。Person
クラスの場合:
public boolean equals(Object obj) {
// same instance
if (obj == this) {
return true;
}
// null
if (obj == null) {
return false;
}
// type
if (!getClass().equals(obj.getClass())) {
return false;
}
// cast and compare state
Person other = (Person) obj;
return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}
再利用可能な汎用ユーティリティクラス:
public final class Equals {
private Equals() {
// private constructor, no instances allowed
}
/**
* Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
*
* @param instance object instance (where the equals() is implemented)
* @param other other instance to compare to
* @param stateAccessors stateAccessors for state to compare, optional
* @param <T> instance type
* @return true when equals, false otherwise
*/
public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
if (instance == null) {
return other == null;
}
if (instance == other) {
return true;
}
if (other == null) {
return false;
}
if (!instance.getClass().equals(other.getClass())) {
return false;
}
if (stateAccessors == null) {
return true;
}
return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
}
}
Person
クラスの場合、このユーティリティクラスを使用します。
public boolean equals(Object obj) {
return Equals.as(this, obj, t -> t.name, t -> t.age);
}
ageがintの場合、==を使用する必要があります。Integerオブジェクトの場合、equals()を使用できます。 equalsをオーバーライドする場合は、ハッシュコードメソッドも実装する必要があります。契約の詳細は、ObjectのjavadocおよびWebのさまざまなページで入手できます。