본문 바로가기
공부하면서 생긴 질문들/Java

Hash code와 toString()

by 구너드 2023. 6. 13.

해시코드: 객체를 식별하는 데 사용되는 정수값. 자바의 모든 객체는 hsahCode() 메서드를 가지고 있으며 이 메서드는 해시코드를 반환한다. 객체의 내용을 기반으로 계산되기 때문에 동일한 내용을 가진 두 개의 객체는 동일한 해시코드를 가져야 한다. 하지만 서로 다른 객체가 동일한 해시코드를 가질 수도 있는데, 이를 해시충돌이라고 한다. 

해시코드의 목적

1. 해시테이블과 같은 자료구조에서 객체를 검색하거나 저장하기 위해 사용.

2. 객체 동등성 비교에 사용될 수 있음.객체의 내용을 비교하기전에 해시코드를 비교하여 비교 연산의 성능 증가

3, 해시 함수의 입력으로 사용

 

자바에서 toString()은 모든 클래스들의 부모 클래스인 Object 클래스에 정의된 메서드이다. 이 메서드는 객체의 문자열 표현을 반환한다. 기본적으로 toString은 클래스이름 @ 해시코드 형식의 문자열을 반환한다.

예시를 살펴보자

 

public class Main {
    public static void main(String[] args) {
        
        int[] answer = {1,2,3,4,5};

        System.out.println(answer);
    }
}
[I@6d311334

answer라는 배열을 직접 프린트했을 경우,  다음과 같은 해시코드가 출력되는 것을 알 수 있다. 그렇다면 그 배열을 직접 출력하고 싶을 때는 

System.out.println(Arrays.toString(answer));

[1, 2, 3, 4, 5]

Arrays.toString을 사용하면 얻을 수 있다. 그렇다면 answer.toString을 출력하게 되면 어떻게 나올까?

 

System.out.println(answer.toString());

[I@6d311334

기존 answer를 직접 입력한 것과 같이 해시코드가 나온다.

 

배열을 출력하고자 할 때, toString만 쓰게 되면, 클래스 이름 @ 해시코드가 나오는데 이는 배열 클래스에서 toString을 재정의하지 않았기 때문이다. 자바의 배열은 Object 클래스를 상속받으며, 따라서 toString()은 배열의 객체 클래스 이름과 해시코드를 반환한다. 따라서 배열의 내용을 출력하기 위해서는 Arrays.toString()을 사용해야한다.


다시 toString()으로 돌아가서 알고리즘 문제를 풀 때, StringBuilder를 String으로 바꿔주려면 toString을 사용해야한다.

다음의 예시를 살펴보자

public class Main {
    public static void main(String[] args) {

        StringBuilder sb = new StringBuilder();

        sb.append("Hello");
        sb.append("My");
        sb.append("Friend");


        System.out.println(sb);
    }
}

 이제 sb를 String클래스로 바꾸어 보자

에러가 발생하는 모습을 볼 수 있다. 

여기서 문자열로 출력하기 위해서 두 가지의 선택을 할 수 있는데 하나씩 살펴보고, 왜 안되는지 그 이유에 대해서 알아보자

 

1.toString()

        String str = sb.toString();
        System.out.println(sb);

StringBuilder 클래스는 문자열을 동적으로 조작하고 연결한다. 이 객체에는 내부적으로 문자열 버퍼가 있어서 문자열을 효율적으로 추가하고 수정할 수 있다. 하지만 이 객체는 문자열을 구성하고 있을 뿐, 최종적인 문자열은 아니다. 따라서 toString()메서드를 사용하여 문자열 버퍼에 있는 데이터를 실제 문자열로 변환해야한다. 


2.String.valueOf()

        String str = String.valueOf(sb);
        System.out.println(sb);

String.valueOf는 다양한 타입의 값을 문자열로 변환하는 데 사용되는 메서드다. 이 메서드는 다양한 타입의 값(기본타입,객체,문자열등)을 입력받아 해당 값을 문자열로 반환한다. 입력된 값의 타입에 따라 다른 동작을 수행하는데 다음과 같은 예시를 들 수 있다.

 

1. 기본 타입 값: 기본 타입인 int, double, boolean 등의 값을 입력하면 해당 값을 해당 타입의 문자열로 변환.

2. 객체: 객체를 입력하면 toString() 메서드를 호출하여 객체를 문자열로 변환.

3.문자열: 이미 문자열인 경우, 입력된 값 그대로 반환.

그렇다면 toString()과 String.valueOf는 뭐가 다른 것일까? 두 개 모두 값을 문자열로 변환하는 목적을 가지고 있지만 몇 가지 차이점이 있다.

 

1.호출 방식

toString은 객체가 이미 존재하는 경우에 사용된다. 객체의 문자열 표현을 얻을 수 있다.

String.valueOf는 입력된 값의 타입에 따라 적절한 변환을 수행한다. 다양한 타입의 값을 입력받을 수 있다.

 

2.기본 동작

toString()은 객체의 문자열 표현을 반환한다. 즉 객체의 클래스에 따라 재정의된 toString()이 호출되면 해당 객체에 대한 설명적인 문자열이 반환된다.

String.valuerOf는 입력된 값에 따라 다른 동작을 수행한다. 기본타입은 해당 값을 문자열로, 객체는 toString()메서드를 호출하여 문자열로, 문자열은 입력된 값 그대로 반환된다.

 

3.Null 처리

toString은 null 객체에 대해 호출하면 NullPointerException이 발생한다.

String.valueOf는 null 값을 입력받을 수 있으면 null을 문자열 null로 반환한다.

'공부하면서 생긴 질문들 > Java' 카테고리의 다른 글

Annotation  (0) 2023.06.14
메모리 영역  (0) 2023.06.14
Transaction  (0) 2023.06.13
Static  (0) 2023.06.13
Interface의 다중 상속  (0) 2023.06.13