Java에서 equals 메소드를 재정의하려고합니다. 나는 수업이 People
기본적으로이 개 데이터 필드가 name
와 age
. 이제 equals
두 사람 객체를 확인할 수 있도록 메서드 를 재정의하고 싶습니다 .
내 코드는 다음과 같습니다.
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 (obj.getClass() != this.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 거짓
-Subash Adhikari-VS-StackOverflow 거짓
-Subash Adhikari-VS-Subash Adhikari 참
-K-VS-StackOverflow 거짓
-K-VS-Subash Adhikari 거짓
-StackOverflow-VS-Subash Adhikari 거짓
-BUILD SUCCESSFUL (총 시간 : 0 초)
답변
매개 변수 유형을 변경하는 새로운 메소드 서명을 도입하는 것을 오버로딩 이라고합니다 .
public boolean equals(People other){
여기는와 People
다릅니다 Object
.
메서드 시그니처가 수퍼 클래스의 시그니처와 동일하게 유지되는 경우이를 재정의 라고 하며 @Override
주석은 컴파일시 두 가지를 구별하는 데 도움이됩니다.
@Override
public boolean equals(Object other){
실제 선언을 보지 않고 age
오류가 나타나는 이유를 말하기가 어렵습니다.
답변
전체 코드를 게시하지 않았기 때문에 세부 사항은 잘 모르겠지만 :
- 재정의하는 것을 잊지 마십시오
hashCode()
하는 것도 equals
방법이 있어야한다Object
하지,People
인수 유형으로. 현재 여러분이 오버로딩하는 것이 아니라 오버로딩하는 것입니다. 특히 나중에 타입을 확인한다면 여러분이 원하는 것이 아닐 것입니다.- 당신이 사용할 수있는
instanceof
예를 들어 People 객체인지 확인하는 데if (!(other instanceof People)) { result = false;}
equals
모든 개체에 사용되지만 기본 요소에는 사용되지 않습니다. 나이가int
(원시적) 이라는 뜻이라고 생각합니다.==
. Integer (대문자 ‘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
}
답변
항목 10 : 등호를 대체 할 때 일반 계약을 준수하십시오.
Effective Java에 따르면
equals
메서드 재정의는 간단 해 보이지만 잘못된 방법은 여러 가지가 있으며 결과는 끔찍할 수 있습니다. 문제를 피하는 가장 쉬운 방법은equals
메서드 를 재정의하지 않는 것 입니다.이 경우 클래스의 각 인스턴스는 자신과 동일합니다. 다음 조건 중 하나가 적용되는 경우 이는 올바른 조치입니다.
-
클래스의 각 인스턴스는 본질적으로 고유 합니다. 이는 값이 아닌 활성 엔티티를 나타내는 Thread와 같은 클래스에 해당됩니다. Object에서 제공하는 equals 구현은 이러한 클래스에 대해 정확히 올바른 동작을합니다.
-
클래스가 “논리적 동등성”테스트를 제공 할 필요가 없습니다. 예를 들어 java.util.regex.Pattern은 두 개의 Pattern 인스턴스가 정확히 동일한 정규식을 나타내는 지 확인하기 위해 equals를 재정의 할 수 있었지만 디자이너는 클라이언트가이 기능을 필요로하거나 원할 것이라고 생각하지 않았습니다. 이러한 상황에서는 Object에서 상속 된 equals 구현이 이상적입니다.
-
수퍼 클래스는 이미 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
.
다음은 고품질 equals 방법을위한 레시피입니다.
-
==
연산자를 사용하여 인수가이 개체에 대한 참조인지 확인합니다. 그렇다면 true를 반환하십시오. 이는 성능 최적화에 불과하지만 잠재적으로 비교 비용이 많이 드는 경우 수행 할 가치가 있습니다. -
instanceof
연산자를 사용하여 인수의 유형이 올바른지 확인하십시오. 그렇지 않은 경우 false를 반환합니다. 일반적으로 올바른 유형은 메서드가 발생하는 클래스입니다. 가끔이 클래스에 의해 구현 된 일부 인터페이스입니다. 클래스가 인터페이스를 구현하는 클래스 간의 비교를 허용하도록 같음 계약을 구체화하는 인터페이스를 구현하는 경우 인터페이스를 사용합니다. Set, List, Map 및 Map.Entry와 같은 컬렉션 인터페이스에는이 속성이 있습니다. -
인수를 올바른 유형으로 캐스트하십시오. 이 캐스트는 instanceof test가 선행되었으므로 성공할 수 있습니다.
-
클래스의 각 “중요한”필드에 대해 인수의 해당 필드가이 개체의 해당 필드와 일치하는지 확인합니다. 이 모든 테스트가 성공하면 true를 반환합니다. 그렇지 않으면 false를 반환합니다. 2 단계의 유형이 인터페이스 인 경우 인터페이스 메서드를 통해 인수의 필드에 액세스해야합니다. 유형이 클래스 인 경우 액세스 가능성에 따라 필드에 직접 액세스 할 수 있습니다.
-
유형이
float
또는 이 아닌 기본 필드의 경우 비교에 연산자를double
사용하십시오==
. 개체 참조 필드의 경우equals
메서드를 재귀 적으로 호출합니다 . 위한float
필드 정적 사용Float.compare(float, float)
방법; 과에 대한double
필드 사용Double.compare(double, double)
. float 및 double 필드의 특수 처리는Float.NaN
,-0.0f
및 유사한 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
또는 다른 throw 가능 객체
비교:
- 유형 검사 : 두 인스턴스가 동일한 유형 이어야 합니다. 즉, 실제 클래스가 동일한 지 비교해야합니다. 개발자
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);
}