ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 같은 value 값을 가지는 String들의 hashcode가 같은 이유
    Java/Basics 2020. 6. 19. 13:31



    같은 value 값을 가지는 String들의 hashcode가 같은 이유가 궁금해졌다.


    hashcode 대해 공부하던 도중 "test"와 new String("test")의 hashcode 값이 


    당연히 다를 줄 알았다. 왜냐하면 hashcode는 객체의 16진수 주소값을 10진수화 


    한 것이기 때문이다. "test"와 new String("test")는 저장되는 영역이 다르기 때문에 주소값도


    다를 것이고 이에 따라 hashcode의 값도 달라야 한다는게 내 생각이었다.


    하지만 결론부터 말하자면, 주소값은 다르지만 hashcode는 같았다. 왜 그럴까?




    ■hashcode 간단 설명 (String에서의 hashcode를 설명하기 위한 빌드업)


    어떤 인스턴스는 주민등록번호와 같은 고유한 값을 가지고 있다. 


    그것이 바로 16진수로 표현된 주소값이다. 


    이 16진수 주소값을 10진수로 변환시킨 것이 hashcode이다. 


    hashcode는 인스턴스마다의 고유한 값이라는 특징 때문에 


    다수의 객체를 다루는 JCF에서 많이 사용된다.


    (왜 16진수를 그대로 사용하지 않고 변환시켜 하는지는 잘 모르겠다)




    ■JCF에서의 String


    그렇다면 String이 JCF의 HashMap에서 사용될 때를 생각해보자.


    - hashMap.put("test", new FirstObject()); 


    - hashMap.put(new String("test"), new SecondObject()); 


    두 경우가 있다. 


    if ("test"와 new String("test")의 hashcode가 같다면) {


    hashMap 내의 "test"에 대한 value는 FirstObject -> SecondObject로 교체된다.


    } else if ("test"와 new String("test")의 hashcode가 다르다면) {


    hashMap 내에 (사용자 입장에서 봤을 때) "test"라는 key로 


    FirstObject, SecondObject 두 value가 저장된다. 


    }


    String 설계자(?)는 else if의 경우 사용자에게 혼란을 일으킬 수 있다고 본 것같다.


    그래서 리터럴 형식과 생성자 형식의 String들을 어느정도 동일하게 취급해야할


    필요성을 느꼈을 것 같다. 이건 직접 얘기를 들어본 것이 아니라서 추측이다!!!


    문득 String 생성자를 한번 열어보고 싶어졌다.


    아래는 일반적으로 가장 많이 사용하는 String 생성자이다.

    public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
    }

    new String("test")의 경우 "test"가 이미 생성된 상태이고, 이미 생성된


    "test"를 String형식으로 받아 그 hash 값과 value를 참조하여 생성된다.


    (리터럴 "test"가 String 타입으로 어떻게 변환되는지 궁금하다. 


    변환될 때 리터럴의 hashCode() 결과값이 hash 필드로 들어갈테니)


    그리고 String의 hashCode 메소드는 아래와 같다.

    public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
    char val[] = value;

    for (int i = 0; i < value.length; i++) {
    h = 31 * h + val[i];
    }
    hash = h;
    }
    return h;
    }

    초기화 될 때의 hash코드를 그대로 반환한다. 즉, 초기화 될 때 리터럴의 hashCode() 값을


    미리 저장시켜 놓은 후 그 값을 계속 사용한다. 




    ■hashcode를 재정의할 때 주의할 점


    hashcode를 재정의 할 때에는 equals 메소드도 함께 재정의해야 부작용이 없다.


    HashMap에서 key값을 판단할 때, hashcode와 equals 메소드의 반환 값이


    같아야 key가 unique하다고 판단하기 때문이다. 


    만약 String 클래스가 hashcode만 재정의되었다고 한다면 


    "test"와 new String("test") 가 모두 key값으로 등록될 수가 있다.


    의도한 key unique에 도달하지 못한 것이다.  

     


    https://m.blog.naver.com/PostView.nhn?blogId=travelmaps&logNo=220930144030&proxyReferer=https:%2F%2Fwww.google.com%2F


    https://jeong-pro.tistory.com/172


    https://www.javaguides.net/2018/07/guide-to-java-string-constant-pool.html

    'Java > Basics' 카테고리의 다른 글

    와일드카드 ? vs 정규 타입 매개변수 T  (0) 2020.07.22
    Java Thread(with Multi Thread)  (0) 2020.06.21
    메모리 주소만으로 Heap의 인스턴스에 접근할 수 있을까?  (2) 2020.06.17
    Java Heap Dump  (0) 2020.06.15
    JVM, JRE, JDK  (0) 2020.06.14

    댓글

Designed by Tistory.