이숭간 공부기록

[Java] Object클래스의 메소드 본문

공부공부/Java

[Java] Object클래스의 메소드

이숭간 2021. 8. 7. 20:39
728x90

Object클래스의 메소드에 대해 알아보자!

Object클래스?

java.lang패키지에 속하는 클래스로 자바 클래스의 최상위 클래스에 해당한다.

우리가 클래스를 선언할때 명시적으로 extends를 사용해서 다른 클래스를 상속하지 않으면 암시적으로 java.lang.Object클래스를 상속한다.

즉 모든 자바의 클래스는 Object클래스의 자식이거나 자손인것이다.


equals() _ 객체비교

  • 함수 매개변수 타입은 Object이다.
    • 모든객체가 매개값이 될수 있음을 의미한다. 모든 객체는 Obejct타입으로 자동타입변환 될 수 있기때문
  • String객체의 equals()메소드가 객체의 번지수가 아닌 논리적인 데이터값을 비교할 수 있었던 이유는 String클래스가 Object의 equals()메소드를 오버라이딩해서 번지비교가 아닌 문자열 비교로 변경했기 때문이다.
    // String 클래스의 equals메소드
    
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) { // 타입체크 먼저 해야한다.
            String aString = (String)anObject; // 같은타입이라면 Obj -> String으로 강제변환
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }
  • 이처럼 일반적으로 Object의 equals()메소드는 직접사용되지않고 하위클래스에서 재정의하여 사용한다.

주의할점

  • equals() 메소드를 재정의할때는 비교객체와 기준객체가 동일한 타입인지 먼저 체크해야한다. 왜냐하면 매개값이 Object이므로 모든 객체가 해당될 수 있기때문에 체크를 통해서 비교가 가능하지 먼저 걸러줘야한다
  • 만약 같다면 Object타입으로 들어온 비교객체를 기준객체 타입으로 강제변환후에 필드값을 비교한다.

hashcode() _ 객체 해시코드

객체 해시코드란 객체를 식별하는 정숫값(주소값)을 말한다.

자바에서 객체의 번지수를 구할때는 직접적인 메모리번지수를 이용하는것이 아니라 해시를 통해 한번 변환된 값을 사용한다.

Object클래스의 hashCode()메소드는 객체의 메모리번지를 이용해 해시코드를 만들어 리턴한다.

HashSet, HashMap, Hashtable에서의 객체동등비교

주의할점은 hashCode값이 갖다고 동등객체라는 보장이 없다. 왜?

해시테이블 자료구조를 생각하면 되는데 서로다른 값을 해시함수에 넣어도 해시값이 충돌될수도 있기 때문이다. 따라서 객체 비교 과정은 다음과 같다.

  1. hashCode()로 리턴된 해시코드값을 비교한다.
    1. 값이 다르다면 다른 객체로 판단한다.
    2. 값이 같다면 equals()메소드로 다시 비교한다.
      1. 값이 다르다면 다른 객체로 판단한다.
      2. 값이 같다면 최종적으로 같은 객체로 판단한다.

String의 hashCode()

같은 문자열일 경우 동일한 해시코드를 리턴한다.

    //String의 hashCode()
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            hash = h = isLatin1() ? StringLatin1.hashCode(value)
                                  : StringUTF16.hashCode(value);
        }
        return h;
    }
    // StringUTF16.java
    
    public static int hashCode(byte[] value) {
        int h = 0;
        int length = value.length >> 1;
        for (int i = 0; i < length; i++) {
            h = 31 * h + getChar(value, i);
        }
        return h;
    }

 


toString() _ 객체 문자 정보

toString()메소드는 해당 인스턴스에 대한 정보를 문자열로 반환한다.

반환되는 문자열은 클래스 이름과 함께 구분자로 '@'가 사용되고 그 뒤로 16진수 해시코드가 추가된다. 16진수 해시코드값은 인스턴스 주소를 가리키는 값이다.

Object의 toString()메소드는 하위클래스에서 오버라이딩하여 의미있는 정보를 리턴하는것을 목적으로 사용된다.

Object obj = new Object();
System.out.println(obj.toString()); //java.lang.Object@75bd9247

java.util.Date의 toString()

Date클래스는 toString()메소드를 오버라이딩해서 현재 시스템의 날짜,시간정보를 리턴한다.

Date d = new Date();
System.out.println(d.toString());
// Sun Aug 08 02:30:35 KST 2021

언제 사용할 수 있을까?

필드의 캡슐화를 더 강력화할수 있지 않을까? 하는 생각이 들었다. ( 수업에서 스치듯 설명해주신것같다!)

 

만약 private으로 선언된 필드를 외부에서 출력할 필요가 있을때 단순히 getter를 선언하고 외부에서 getter를 호출해서 필드값을 얻어가는경우, 어쨌든 외부에서 이 필드에 접근하도록하고 출력에 대한 권한을 외부에 위임한것이 된다.

 

반면 getter대신 toString()메소드를 오버라이딩하면 출력에 대한 권한을 객체 스스로에게 줄 수 있게된다. 따라서 private필드를 객체내부에서만 관리할 수 있게되므로(?) 더 결합도낮고 응집도높은 코드를 작성할 수 있을것같다.