Java 8-같음 및 해시 코드에 대한 기본 메서드

토마스 77

default구현 equals(Object)hashCode()예측 가능한 방식으로 인터페이스에 메서드를 만들었습니다 . 리플렉션을 사용하여 유형 (클래스)의 모든 필드를 반복하여 값을 추출하고 비교합니다. 코드는 Apache Commons Lang HashCodeBuilderEqualsBuilder.

문제는 내 테스트에서 이러한 메서드를 처음 호출 할 때 첫 번째 호출에서 훨씬 더 많은 시간이 걸린다는 것을 보여줍니다. 타이머는 System.nanoTime(). 다음은 로그의 예입니다.

Time spent hashCode: 192444
Time spent hashCode: 45453
Time spent hashCode: 48386
Time spent hashCode: 50951

실제 코드 :

public interface HashAndEquals {

    default <T> int getHashCode(final T type) {
        final List<Field> fields = Arrays.asList(type.getClass().getDeclaredFields());
        final HashCodeBuilder builder = new HashCodeBuilder(31, 7);
        fields.forEach( f -> {
            try {
                f.setAccessible(true);
                builder.append(f.get(type));
            } catch (IllegalAccessException e) {
                throw new GenericException(e.toString(), 500);
            }
        });
        return builder.toHashCode();
    }

    default <T, K> boolean isEqual(final T current, final K other) {
        if(current == null || other == null) {
            return false;
        }
        final List<Field> currentFields = Arrays.asList(current.getClass().getDeclaredFields());
        final List<Field> otherFields = Arrays.asList(other.getClass().getDeclaredFields());
        final IsEqual isEqual = new IsEqual();
        isEqual.setValue(true);
        currentFields.forEach(c -> otherFields.forEach(o -> {
            c.setAccessible(true);
            o.setAccessible(true);
            try {
                if (o.getName().equals(c.getName())) {
                    if (!o.get(other).equals(c.get(current))) {
                        isEqual.setValue(false);
                    }
                }
            } catch (IllegalAccessException e) {
                isEqual.setValue(false);
            }
        }));
        return isEqual.getValue();
    }
}

이러한 메서드를 사용하여 hashCodeequals다음 을 구현하는 방법 :

@Override
public int hashCode() {
    return getHashCode(this);
}

@Override
public boolean equals(Object obj) {
    return obj instanceof Step && isEqual(this, obj);
}

테스트의 예 :

    @Test
public void testEqualsAndHashCode() throws Exception {
    Step step1 = new Step(1, Type.DISPLAY, "header 1", "description");
    Step step2 = new Step(1, Type.DISPLAY, "header 1", "description");
    Step step3 = new Step(2, Type.DISPLAY, "header 2", "description");
    int times = 1000;
    long total = 0;

    for(int i = 0; i < times; i++) {
        long start = System.nanoTime();
        boolean equalsTrue = step1.equals(step2);
        long time = System.nanoTime() - start;
        total += time;
        System.out.println("Time spent: " + time);
        assertTrue( equalsTrue );
    }
    System.out.println("Average time: " + total / times);

    for(int i = 0; i < times; i++) {
        assertEquals( step1.hashCode(), step2.hashCode() );
        long start = System.nanoTime();
        System.out.println(step1.hashCode() + " = " + step2.hashCode());
        System.out.println("Time spent hashCode: " + (System.nanoTime() - start));
    }
    assertFalse( step1.equals(step3) );
} 

이러한 메서드를 인터페이스에 넣는 이유는 가능한 한 유연하기 때문입니다. 내 클래스 중 일부는 상속이 필요할 수 있습니다.

내 테스트에 따르면 해시 코드와 같음 모두 동일한 내부 상태를 가진 객체에 대해 항상 동일한 값을 반환한다고 믿을 수 있습니다.

내가 알고 싶은 것은 내가 뭔가를 놓치고 있는지입니다. 그리고 이러한 방법의 동작을 신뢰할 수 있다면? ( LombokAutoValue 프로젝트가 이러한 방법을 구현하는 데 도움이 된다는 것을 알고 있지만 제 클라이언트는 이러한 라이브러리에 너무 열중하지 않습니다).

메서드 호출을 처음 수행하는 데 항상 약 5 배 더 오래 걸리는 이유에 대한 통찰력도 매우 유용 할 것입니다.

홀거

여기에는 default메서드에 특별한 것이 없습니다 . 이전에 사용되지 않은 클래스에서 처음으로 메소드를 호출하면 호출이 클래스로드, 확인 및 클래스 초기화를 트리거하고 메소드 실행은 JIT 컴파일러 / 핫스팟 최적화 프로그램이 시작되기 전에 해석 모드에서 시작됩니다. 의 메소드 가 호출 interface될 때 실제로 사용될 때까지 다른 단계는 여전히 지연되고 있습니다 . 처음으로.defaultinterface

최초 실행이 후속 실행보다 더 많은 시간이 소요되는 것은 Java의 정상적인 현상입니다. 귀하의 경우 런타임에 기능적 인터페이스 구현이 생성 될 때 추가 첫 번째 오버 헤드가있는 람다 식을 사용하고 있습니다.

코드는 default메서드 보다 오래 존재하는 일반적인 안티 패턴입니다 . 와 클래스 "구현" 사이 에는 is-a 관계 가 없습니다 HashAndEquals. 이 두 유틸리티 메서드를 static전용 클래스의 메서드로 대신 제공하고 import static선언 클래스를 앞에 추가하지 않고 이러한 메서드를 호출하려는 경우 사용할 수 있습니다 (그리고 그래야합니다) .

.NET Framework에서 이러한 메서드를 상속해도 이점이 없습니다 interface. 결국 각 클래스는 재정의해야 Object.hashCode하며 Object.equals어쨌든 이러한 유틸리티 메서드를 사용할지 여부를 신중하게 선택할 수 있습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

CXF JAXB 기본 같음 / 해시 코드

분류에서Dev

엔터티의 해시 코드와 같음 및 toString 메서드에 관한 질문

분류에서Dev

Collections.synchronizedX의 결과에 대해 Java 8 Collection 기본 메서드를 호출해도 안전합니까?

분류에서Dev

다음 코드에 대해 기본 창 대신 MVVM 사용

분류에서Dev

Java-기본 및 파생 클래스에 대한 메서드 복제 구현 방법

분류에서Dev

Java 코드에 대한 Windows 및 Linux의 경로 구분 기호

분류에서Dev

mongoid 해시 필드에 대한 기본 해시 키 설정

분류에서Dev

Emacs 및 gdb-역 추적 기능에 대한 코드 표시

분류에서Dev

IntelliJ IDEA에서 Java8 코드가 해결되지 않음

분류에서Dev

다양한 유형 및 해당 기본 클래스에 대한 오버로드

분류에서Dev

기본 클래스 메서드에 대한 std :: bind 및 비가 상 호출

분류에서Dev

클래스의 같음 및 해시 코드 메서드를 재정의하지 않고 목록에서 중복 개체 제거

분류에서Dev

Java에서 2,4,8, ..에 대한 재귀 메서드

분류에서Dev

Java 8 기본 메소드 상속

분류에서Dev

https://docs.google.com 반환 코드 401에 대한 요청 실패-Google 스프레드 시트에서 PDF 파일 저장 및 이메일 보내기

분류에서Dev

같음 및 해시 코드를 통해 하위 클래스 구분

분류에서Dev

getter 및 setter 메서드에 대한 기본 javadoc을 만드는 IntelliJ 바로 가기

분류에서Dev

Java 8 및 Maven 3.2.3을 사용하여 코드를 컴파일하려고 할 때 내 댓글에 대해 이상한 오류가 발생합니다.

분류에서Dev

Java 8 및 Maven 3.2.3을 사용하여 코드를 컴파일하려고 할 때 내 댓글에 대해 이상한 오류가 발생합니다.

분류에서Dev

내부 클래스를 사용하여 Java / 내부 메서드 가시성에서 외부 클래스에 대한 개인 레코드 만들기

분류에서Dev

Java 8 바이트 코드 인터페이스의 기본 메소드 표시 방법

분류에서Dev

Jackson @JsonIgnore an 상속 된 Java 8 기본 메서드

분류에서Dev

C ++ : 메서드에 대한 기본 질문 및 "이미 본문이 있습니다"오류

분류에서Dev

utf8 및 wctomb에 대한 유니 코드 코드 포인트

분류에서Dev

"<"및 ">"에 대한 KeyListener 코드

분류에서Dev

수퍼 클래스의 같음 및 해시 코드 메서드를 재정의합니다. 하위 클래스를 위해 수행합니까

분류에서Dev

기본 유형 및 레코드에 대한 DAML의 기본값을 어떻게 지정합니까?

분류에서Dev

Elasticsearch에서 인덱스에 대한 기본 및 복제본 노드 할당

분류에서Dev

파일에서 xaml 코드로 그리드를로드 한 다음 기본 코드에서 활성화

Related 관련 기사

  1. 1

    CXF JAXB 기본 같음 / 해시 코드

  2. 2

    엔터티의 해시 코드와 같음 및 toString 메서드에 관한 질문

  3. 3

    Collections.synchronizedX의 결과에 대해 Java 8 Collection 기본 메서드를 호출해도 안전합니까?

  4. 4

    다음 코드에 대해 기본 창 대신 MVVM 사용

  5. 5

    Java-기본 및 파생 클래스에 대한 메서드 복제 구현 방법

  6. 6

    Java 코드에 대한 Windows 및 Linux의 경로 구분 기호

  7. 7

    mongoid 해시 필드에 대한 기본 해시 키 설정

  8. 8

    Emacs 및 gdb-역 추적 기능에 대한 코드 표시

  9. 9

    IntelliJ IDEA에서 Java8 코드가 해결되지 않음

  10. 10

    다양한 유형 및 해당 기본 클래스에 대한 오버로드

  11. 11

    기본 클래스 메서드에 대한 std :: bind 및 비가 상 호출

  12. 12

    클래스의 같음 및 해시 코드 메서드를 재정의하지 않고 목록에서 중복 개체 제거

  13. 13

    Java에서 2,4,8, ..에 대한 재귀 메서드

  14. 14

    Java 8 기본 메소드 상속

  15. 15

    https://docs.google.com 반환 코드 401에 대한 요청 실패-Google 스프레드 시트에서 PDF 파일 저장 및 이메일 보내기

  16. 16

    같음 및 해시 코드를 통해 하위 클래스 구분

  17. 17

    getter 및 setter 메서드에 대한 기본 javadoc을 만드는 IntelliJ 바로 가기

  18. 18

    Java 8 및 Maven 3.2.3을 사용하여 코드를 컴파일하려고 할 때 내 댓글에 대해 이상한 오류가 발생합니다.

  19. 19

    Java 8 및 Maven 3.2.3을 사용하여 코드를 컴파일하려고 할 때 내 댓글에 대해 이상한 오류가 발생합니다.

  20. 20

    내부 클래스를 사용하여 Java / 내부 메서드 가시성에서 외부 클래스에 대한 개인 레코드 만들기

  21. 21

    Java 8 바이트 코드 인터페이스의 기본 메소드 표시 방법

  22. 22

    Jackson @JsonIgnore an 상속 된 Java 8 기본 메서드

  23. 23

    C ++ : 메서드에 대한 기본 질문 및 "이미 본문이 있습니다"오류

  24. 24

    utf8 및 wctomb에 대한 유니 코드 코드 포인트

  25. 25

    "<"및 ">"에 대한 KeyListener 코드

  26. 26

    수퍼 클래스의 같음 및 해시 코드 메서드를 재정의합니다. 하위 클래스를 위해 수행합니까

  27. 27

    기본 유형 및 레코드에 대한 DAML의 기본값을 어떻게 지정합니까?

  28. 28

    Elasticsearch에서 인덱스에 대한 기본 및 복제본 노드 할당

  29. 29

    파일에서 xaml 코드로 그리드를로드 한 다음 기본 코드에서 활성화

뜨겁다태그

보관