EffectiveJava - 모든 객체에 공통적인 메서드

5234 단어 대상HashCode
비록 Object는 구체적인 유형이지만 그의 디자인은 주로 확장을 위한 것이다. 그의 모든 비final 방법: - equals-hashCode-tostring-clone-finalize
모두 명확한 통용 약정이 있다 (general cantract)

제8조 equals 덮어쓰기 방법 시 통용 약정 준수


equals 방법을 덮어쓰지 않을 때, 클래스의 모든 실례는 그 자체와 같다
다음 경우 equeal 방법을 덮어쓰지 않아도 됩니다. -클래스의 모든 실례는 본질적으로 유일한 것이다. 예를 들어 Thread - 클래스가'논리적 상등(logical equality)'의 테스트 기능을 제공했는지에 관심이 없다. 예를 들어 Random은 equals 방법을 실현하여 두 Random이 발생하는 무작위 수가 같은지 판단하는데 사용하지만 디자이너는 클라이언트가 이런 기능을 필요로 하거나 기대한다고 생각하지 않는다.이러한 상황에서 Object의 equals 방법을 계승하고 수요를 충족시킬 수 있다. - 슈퍼클래스가 equals 방법을 덮어쓰고 슈퍼클래스에서 계승된 행위는 하위 클래스에 적합하다. - 클래스는 사유하거나 패키지급의 사유이기 때문에 그의 equal 방법은 영원히 호출되지 않을 것이다. - 클래스는 equals 방법을 덮어쓰지 않아도 된다. 즉, 모든 값에 하나의 대상이 존재한다.
만약에 클래스가 자신만의 논리적 상등 개념을 가지고 있고 클래스가 equals가 원하는 행위를 커버하지 않았다면 이럴 때 우리는 equals 방법을 실현해야 한다.
다음은 equals의 통용규범-자반성-reflexive: 모든 비null의 인용값 x에 대해 x.equals(x)는true-대칭성-symmetric로 되돌아와야 한다. 그 어떠한 비null의 인용값 x와 y에 대해서도 y.equals(x)가true로 되돌아갈 때만 x.equals(y)는true-전달성-transitive: 비null의 인용값 x, y, z, 만약x.equals(x.equals)가true로 되돌아와truequals(y)로 되돌아와truequals)로 되돌아간다.그러면 x.equals(z)도ture-일치성-consistent로 되돌아와야 합니다. 모든 비null의 인용값 x와 y에 대해 equals의 비교 작업이 대상에서 사용된 정보가 수정되지 않으면 x.equals(y)를 여러 번 호출하면 똑같은 결과를 일치시켜야 합니다. - 비null의 값은 x를 인용하고 x.equals(null)는false로 되돌아와야 합니다.
어떻게 고품질의 equals 방법을 실현합니까?우선 ==조작부호를 사용하여 파라미터가 이 대상의 인용인지 확인합니다.true로 직접 되돌아오는 것은 성능 최적화입니다.instanceof를 사용하여 매개 변수 형식을 검사합니다.매개 변수를 정확한 형식으로 변환하기 4.이 클래스의 모든 관건적인 영역에 대해 매개 변수의 영역이 이 대상의 영역과 같은지 검사합니다.queals 방법을 작성한 후에 자신에게 그것이 대칭적이고 전달되며 일치하는지 물어봐야 한다.6. equals 방법을 덮어쓸 때hashCode 방법을 덮어씁니다.equals 방법을 지나치게 스마트하게 하지 마라.equals 메서드에서 선언한 Object 매개 변수를 다른 유형으로 바꾸지 마십시오. (실제로 이것은 덮어쓰지 않습니다.)
다음 예제에서는 다음과 같이 하십시오.
     public static class PhoneNumber {

        private final int areaCode;
        private final int prefix;
        private final int lineNumber;

        public PhoneNumber(int areaCode, int prefix, int lineNumber) {
            this.areaCode = areaCode;
            this.prefix = prefix;
            this.lineNumber = lineNumber;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (!(obj instanceof PhoneNumber)) {
                return false;
            }
            PhoneNumber phoneNumber = (PhoneNumber) obj;
            return phoneNumber.areaCode == areaCode && phoneNumber.prefix == prefix && phoneNumber.lineNumber == lineNumber;
        }
    }

자세한 내용은 EffectiveJava 참조

제9조: equals를 덮어쓸 때 항상hashCode를 덮어써야 한다


equals를 덮어쓸 때hashCode를 덮어써야 합니다. 그렇지 않으면 Object를 위반합니다.hashCode의 일반적인 규정으로 인해 이 종류는 산열 기반의 모든 집합과 결합하여 정상적으로 작업을 할 수 없다. 이런 집합은HashMap,HashSet,HashTable를 포함한다.
hashCode는 다음과 같은 약정이 있다. - 응용 프로그램이 실행되는 동안 대상의 equals 방법의 비교 작업에 사용된 정보가 수정되지 않으면 이 대상에 대해hashCode 방법을 여러 번 호출하면 항상 같은 정수를 되돌려야 한다(같은 응용 프로그램이 여러 번 실행하는 과정에서 일치하지 않을 수 있다).만약에 두 대상이 equals 방법에 따라 비교가 같다면 두 대상의 임의의hashCode 방법을 호출하면 모두 같은 정수 결과를 만들어야 한다. - 만약에 두 대상이 equals 방법에 따라 비교하는 것이 같지 않다면 두 대상의 임의의hashCode 방법을 호출하면 반드시 다른 정수 결과를 만들어야 하는 것은 아니다.
그러나 프로그래머는 서로 다른 대상에게 확연히 다른 정수 결과를 만들어 산목록(hash table)의 성능을 향상시킬 수 있다는 것을 알아야 한다.
8조에 제시된 예: PhoneNumber:
        HashMap<PhoneNumber, String> hashMap = new HashMap<>();
        hashMap.put(new PhoneNumber(204, 132, 255), "ztiany");

        String s = hashMap.get(new PhoneNumber(204, 132, 255));
        System.out.print(s);
 :null

PhoneNumber가hashCode 방법을 덮어쓰지 않았기 때문에 같은 전화번호에 따라 저장된 연락처로 돌아가면null로 돌아갑니다.
따라서 hashCode 방법을 덮어쓰기만 하면 됩니다.
        @Override
        public int hashCode() {
            return 42;
        }

이 때 우리는 문자열'ztiany '를 얻을 수 있습니다.
그러나hashCode를 덮어쓰는 방법은 매우 나쁘다. 모든 대상이 같은 산열 코드를 가지기 때문에 모든 대상이 같은 산열통에 비치고 산열을 체인 테이블 구조로 퇴화시킨다.
좋은 산목록 함수는 일반적으로 '서로 다른 대상을 위해 서로 다른 산열 코드를 만드는 것' 을 경향한다.이상적인 상황에서 집합 중의 서로 다른 실을 모든 가능한 산열치에 고르게 나누지 못하게 해야 한다. 이런 이상적인 상황에 도달하기는 매우 어렵지만 이런 이상적인 상황에 접근하는 것은 결코 어렵지 않다. 다음은 간단한 해결 방법이다.
  • 0이 아닌 정수, 예를 들어 17을 Result의 int 형식으로 저장하는 변수
  • 객체의 각 주요 도메인 f(equals에 포함된 각 도메인)에 대해 다음 단계를 완료합니다.
  • boolean 유형이라면 계산: f?1:0
  • byte,char,short 또는 int 형식이라면 계산: (int)f
  • long 형식이라면 (int)(f^(f>>>32));
  • flat 유형인 경우 Float.floatToIntBits(f);
  • 더블유형이면 Doul, 더블투롱비트(f),
  • 대상이 인용하고 이 종류의 equals 방법은 귀속 호출 equals 방법을 통해 이 필드를 비교하면 이 필드의 귀속 호출hashCode
  • 배열이면 Arrays.HashCode

  • 마지막으로 아래 공식에 따라 상기 규칙을 합병하여 계산한 결과 c는result에 합병되었다. resut = 31*result+c;
  • result
  • 반환
  • 컴파일러 테스트, 검증
  • 예를 들어 다중 위 PhoneNumber는 다음과 같은 hashCode 방법을 사용할 수 있습니다.
       @Override
            public int hashCode() {
                int result = 17;
                result  = 31 *result + areaCode;
                result  = 31 *result + prefix;
                result  = 31 *result + lineNumber;
                System.out.println(result);
                return result;
            }
    

    제10조: 항상 toString을 덮어써야 한다


    toString 방법을 덮어쓰고 일정한 규칙을 준수하면 클래스를 더욱 편안하게 사용할 수 있으며 인쇄 대상을 인쇄할 때 인쇄 결과가 더욱 직관적이고 의미가 있다.

    좋은 웹페이지 즐겨찾기