내가 아는 궁금 사용하여 여기에 대해 어떤 사람을 생각
org.apache.commons.lang.builder
EqualsBuilder
/ HashCodeBuilder
이행을위한 equals
/를 hashCode
? 직접 작성하는 것보다 더 나은 방법일까요? Hibernate와 잘 작동합니까? 당신의 의견은 무엇입니까?
내가 아는 궁금 사용하여 여기에 대해 어떤 사람을 생각
org.apache.commons.lang.builder
EqualsBuilder
/ HashCodeBuilder
이행을위한 equals
/를 hashCode
? 직접 작성하는 것보다 더 나은 방법일까요? Hibernate와 잘 작동합니까? 당신의 의견은 무엇입니까?
답변:
commons / lang 빌더는 훌륭하며 몇 년 동안 눈에 띄는 성능 오버 헤드 (최대 절전 모드 유무에 관계없이)를 사용해 왔습니다. 그러나 Alain이 쓴 것처럼 구아바 방식은 훨씬 좋습니다.
다음은 샘플 Bean입니다.
public class Bean{
private String name;
private int length;
private List<Bean> children;
}
Commons / Lang으로 구현 된 equals () 및 hashCode ()는 다음과 같습니다.
@Override
public int hashCode(){
return new HashCodeBuilder()
.append(name)
.append(length)
.append(children)
.toHashCode();
}
@Override
public boolean equals(final Object obj){
if(obj instanceof Bean){
final Bean other = (Bean) obj;
return new EqualsBuilder()
.append(name, other.name)
.append(length, other.length)
.append(children, other.children)
.isEquals();
} else{
return false;
}
}
Java 7 이상 (구아바에서 영감을 얻음)과 함께 여기 :
@Override
public int hashCode(){
return Objects.hash(name, length, children);
}
@Override
public boolean equals(final Object obj){
if(obj instanceof Bean){
final Bean other = (Bean) obj;
return Objects.equals(name, other.name)
&& length == other.length // special handling for primitives
&& Objects.equals(children, other.children);
} else{
return false;
}
}
참고 :이 코드는 원래 구아바를 참조했지만 주석에서 지적 했듯이이 기능은 JDK에 도입되었으므로 더 이상 구아바가 필요하지 않습니다.
보시다시피 Guava / JDK 버전은 더 짧고 불필요한 도우미 객체를 피합니다. 같으면 이전 Object.equals()
호출이 false를 반환 하면 평가를 단락 할 수 있습니다 (공평하게 : commons / lang에는 위와 같이 단락을 허용 ObjectUtils.equals(obj1, obj2)
하는 대신 사용할 수있는 동일한 의미를 갖는 방법이 있습니다 EqualsBuilder
).
그렇습니다. 공통 랭 빌더는 수동으로 구성 equals()
하고 hashCode()
메소드 (또는 Eclipse가 생성 할 끔찍한 괴물) 보다 매우 바람직 하지만 Java 7 + / Guava 버전이 훨씬 좋습니다.
그리고 최대 절전 모드에 대한 참고 사항 :
equals (), hashCode () 및 toString () 구현에서 게으른 컬렉션 사용에주의하십시오. 열린 세션이 없으면 비참하게 실패합니다.
참고 (about equals ()) :
a) 위의 equals () 버전 모두에서 다음 단축키 중 하나 또는 둘 다를 사용할 수 있습니다.
@Override
public boolean equals(final Object obj){
if(obj == this) return true; // test for reference equality
if(obj == null) return false; // test for null
// continue as above
b) equals () 계약에 대한 해석에 따라 라인을 변경할 수도 있습니다
if(obj instanceof Bean){
에
// make sure you run a null check before this
if(obj.getClass() == getClass()){
두 번째 버전을 사용하는 경우 메소드 super(equals())
내부 에서 호출하려고 할 수도 있습니다 equals()
. 여기에 의견이 다르 므로이 질문에서 주제에 대해 설명합니다.
(그것에 대해 비록 hashCode()
, 동일 적용 equals()
)
Objects.hashCode(..)
Arrays.hashCode(...)
기본 필드가 많은 경우 ( 기본과 같이 ) 성능이 저하 될 수 있습니다. 이러한 경우 EqualsBuilder
실제로 더 나은 솔루션 일 수 있습니다.
equals
. 구아바는 모든 값을 객체로 변환하고 commons-lang은 단 하나의 새로운 객체 만 만듭니다.
여러분, 일어나요! Java 7부터 표준 라이브러리에는 equals 및 hashCode 에 대한 도우미 메소드가 있습니다. 그들의 사용법은 구아바 방법의 사용법과 완전히 같습니다.
타사 라이브러리에 의존하지 않고 (자원이 제한된 장치를 실행 중일 수도 있음) 자신 만의 방법을 입력하고 싶지 않은 경우 IDE를 사용하여 작업을 수행 할 수도 있습니다 (예 : 일식 사용)
Source -> Generate hashCode() and equals()...
원하는대로 구성 할 수 있고 변경 사항 을 지원 해야하는 '기본'코드 가 제공됩니다.
예 (일부 Juno) :
import java.util.Arrays;
import java.util.List;
public class FooBar {
public String string;
public List<String> stringList;
public String[] stringArray;
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((string == null) ? 0 : string.hashCode());
result = prime * result + Arrays.hashCode(stringArray);
result = prime * result
+ ((stringList == null) ? 0 : stringList.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
FooBar other = (FooBar) obj;
if (string == null) {
if (other.string != null)
return false;
} else if (!string.equals(other.string))
return false;
if (!Arrays.equals(stringArray, other.stringArray))
return false;
if (stringList == null) {
if (other.stringList != null)
return false;
} else if (!stringList.equals(other.stringList))
return false;
return true;
}
}
equals
. 타사 라이브러리에 의존하지 않으려면 Objects.equal
자신 과 같은 한 줄 방법을 작성 하십시오. 한두 번만 사용하더라도 코드가 더 나아집니다!
equals
/ hashCode
한 줄 방법 ???
EqualsBuilder 및 HashCodeBuilder에는 수동으로 작성된 코드와 다른 두 가지 주요 측면이 있습니다.
EqualsBuilder 및 HashCodeBuilder를 사용하면 null 일 수있는 필드를 쉽게 비교할 수 있습니다. 수동으로 작성된 코드를 사용하면 많은 상용구가 생성됩니다.
반면 EqualsBuilder는 equals 메소드 호출 당 인스턴스를 작성합니다. equals 메소드가 자주 호출되면 많은 인스턴스가 작성됩니다.
최대 절전 모드의 경우 equals 및 hashCode 구현은 차이가 없습니다. 그것들은 단지 구현 세부 사항입니다. 최대 절전 모드로로드 된 거의 모든 도메인 오브젝트의 경우, 빌더의 런타임 오버 헤드 (이스케이프 분석이없는 경우도)는 무시할 수 있습니다 . 데이터베이스 및 통신 오버 헤드가 상당합니다.
skaffman이 언급했듯이 리플렉션 버전은 프로덕션 코드에서 사용할 수 없습니다. 성찰이 느려지고 "구현"이 가장 단순한 수업 이외의 모든 사람에게는 정확하지 않을 것입니다. 새로 소개 된 회원이 평등 방식을 변경함에 따라 모든 회원을 고려하는 것도 위험합니다. 리플렉션 버전은 테스트 코드에서 유용 할 수 있습니다.
직접 작성하지 않으면 Google 구아바 (이전의 Google 컬렉션) 를 사용할 수도 있습니다
id가 기본 키인 엔티티 bean을 처리하는 경우 단순화 할 수 있습니다.
@Override
public boolean equals(Object other)
{
if (this == other) { return true; }
if ((other == null) || (other.getClass() != this.getClass())) { return false; }
EntityBean castOther = (EntityBean) other;
return new EqualsBuilder().append(this.getId(), castOther.getId()).isEquals();
}
제 생각에는 Hibernate, 특히 일부 엔티티의 길이, 이름 및 자녀를 비교하는 답변의 예와 잘 어울리지 않습니다. Hibernate 는 비즈니스 키 를 사용하여 equals () 및 hashCode ()에서 사용하도록 권장 하며 그 이유가 있습니다. 비즈니스 키에서 auto equals () 및 hashCode () 생성기를 사용하는 경우 괜찮습니다. 앞에서 언급 한 것처럼 성능 문제 만 고려하면됩니다. 그러나 사람들은 일반적으로 IMO가 매우 잘못된 모든 속성을 사용합니다. 예를 들어 현재 @AutoProperty와 함께 Pojomatic을 사용하여 엔터티를 작성하는 프로젝트를 진행하고 있습니다.
hashCode () 및 equals ()를 사용하는 두 가지 주요 시나리오는 다음과 같습니다.
엔티티가 다음과 같다고 가정 해 봅시다.
class Entity {
protected Long id;
protected String someProp;
public Entity(Long id, String someProp);
}
Entity entity1 = new Entity(1, "a");
Entity entity2 = new Entity(1, "b");
둘 다 어느 시점에서 어떤 세션에서 가져온 Hibernate와 동일한 엔티티입니다 (그들의 id와 클래스 / 테이블은 동일합니다). 그러나 모든 소품에 auto equals () 해시 코드 ()를 구현하면 무엇을 가질 수 있습니까?
따라서 99 %의 프로젝트를 위해 Hibernate 개념과 일치하는 기본 엔터티 클래스에서 한 번 작성된 equals () 및 hashCode () 구현을 사용합니다.
@Override
public boolean equals(Object obj) {
if (StringUtils.isEmpty(id))
return super.equals(obj);
return getClass().isInstance(obj) && id.equals(((IDomain) obj).getId());
}
@Override
public int hashCode() {
return StringUtils.isEmpty(id)
? super.hashCode()
: String.format("%s/%s", getClass().getSimpleName(), getId()).hashCode();
}
과도 엔티티의 경우 지속 단계에서 Hibernate가 수행하는 것과 동일한 작업을 수행합니다. 인스턴스 일치를 사용합니다. 영속 객체의 경우 고유 키, 즉 테이블 / ID를 비교합니다 (복합 키는 절대 사용하지 않습니다).
다른 사람들이 유용하다고 생각하는 경우 위에서 언급 한 추가 객체 생성 오버 헤드를 피하는 해시 코드 계산을 위해이 도우미 클래스를 생각해 냈습니다. 실제로 Objects.hash () 메서드의 오버 헤드는 각 레벨마다 새로운 배열을 만들 것입니다!).
사용 예 :
public int hashCode() {
return HashCode.hash(HashCode.hash(timestampMillis), name, dateOfBirth); // timestampMillis is long
}
public int hashCode() {
return HashCode.hash(super.hashCode(), occupation, children);
}
HashCode 도우미 :
public class HashCode {
public static int hash(Object o1, Object o2) {
return add(Objects.hashCode(o1), o2);
}
public static int hash(Object o1, Object o2, Object o3) {
return hash(Objects.hashCode(o1), o2, o3);
}
...
public static int hash(Object o1, Object o2, ..., Object o10) {
return hash(Objects.hashCode(o1), o2, o3, ..., o10);
}
public static int hash(int initial, Object o1, Object o2) {
return add(add(initial, o1), o2);
}
...
public static int hash(int initial, Object o1, Object o2, ... Object o10) {
return add(... add(add(add(initial, o1), o2), o3) ..., o10);
}
public static int hash(long value) {
return (int) (value ^ (value >>> 32));
}
public static int hash(int initial, long value) {
return add(initial, hash(value));
}
private static int add(int accumulator, Object o) {
return 31 * accumulator + Objects.hashCode(o);
}
}
나는 10이 도메인 모델에서 최대의 합리적인 속성 수라는 것을 알았습니다. 더 많은 것이 있으면 문자열과 프리미티브 힙을 유지하는 대신 리팩토링하고 더 많은 클래스를 도입해야한다고 생각합니다.
단점은 다음과 같습니다. 주로 기본 요소 및 / 또는 배열을 깊이 해시해야하는 경우 유용하지 않습니다. (일반적으로 제어 할 수없는 평평한 (전송) 객체를 처리해야 할 경우)
reflectionEquals
andreflectionHashcode
함수에 유혹을받지 마십시오 . 성능은 절대적인 킬러입니다.