[기본 개념] 4 | (1.1) Object 클래스의 메서드

728x90

[기본 개념] 4 | (1.1) Object 클래스의 메서드

1> Object클래스

2 String클래스

3 StringBuffer클래스와 StringBuilder클래스

4 Math클래스

5 래퍼(wrapper)클래스

1. Object클래스(1)

Object클래스는 모든 클래스의 최고 조상이기 때문에 모든 클래스에서 바로 사용 가능하다.

 

Object클래스의 메서드 설명
protected Object clone( ) 객체 자신의 복사본을 반환한다.
public boolean equals(Object obj) 객체 자신과 obi가 같은 객체인지 알려준다.(같으면 true)
protected void finalize( ) 객체가 소멸될 때 가비지 컬렉터에 의해 자동적으로 호출된다. 이 때 수행되어야 하는 코드가 있을 때 오버라이딩한다.(거의 사용안함)
public Class getClass( ) 객체 자신의 클래스 정보를 담고 있는 Class인스턴스를 반환한다.
public int hashCode( ) 객체 자신의 해시코드를 반환한다.
public String toString( ) 객체 자신의 정보를 문자열로 반환한다.
public void notify( ) 객체 자신을 사용하려고 기다리는 쓰레드 하나만 깨운다.
public void notifyAll( ) 객체 자신을 사용하려고 기다리는 모든 쓰레드를 깨운다.
public void wait( )
public void wait(long timeout)
public void wait(long timeout, int nanos)
다른 쓰레드가 notify( )나 notifyAll( )을 호출할 때까지 현재 쓰레드를 무한히 또는 지정된 시간(timeout, nanos)동안 기다리게 한다.
(timeout은 천분의 1초, nanos는 10^9분의 1초)

 

equls(Object obj)

매개변수로 객체의 참조변수를 받아서 비교해 결과를 boolean값으로 알려주는 역할이다.

 

public boolean equals(Object obj) {

        return(this == obj) ;

}

 

 두 객체의 같고 다름을 참조변수의 값으로 판단한다. 따라서 서로 다른 두 객체를 equals메서드로 비교하면 항상 false를 얻게 된다.

 

 객체를 생성할 때, 메모리의 비어있는 공간을 찾아 생성하므로 서로 다른 두 개의 객체가 같은 주소를 갖는 일은 없다. 다만 두 개 이상의 참조변수가 같은 주소값을 갖는 것(한 객체를 참조)은 가능하다.

 

        Value v1 = new Value(10) ;

        Value v2 = new Value(10) ;

 

 이렇게 있을 때, v1과 v2를 equals메서드를 이용해서 비교하게 되면 주소값으로 비교하기 때문에 value의 값이 둘 다 10으로 같아도 false이다.

 

 하지만 v2 = v1 ; 을 수행하면 v2는 v1이 참조하고 있는 인스턴스의 주소값이 저장되므로 v1.equals(v2)의 결과가 true가 된다.

 

 equals메서드로 Value인스턴스가 가지고 있는 value값을 비교하도록 하려면 Value클래스에서 equals메서드를 오버라이딩하여 주소가 아닌 객체에 저장된 내용을 비교하도록 하면 된다.

 

예제/EqualsEx2.java

class Person {
    long id;

    public boolean equals(Object obj) {
        if (obj instanceof Person)
            return id == ((Person)obj).id;      // obj가 Object타입이므로 id를 참조하려면
        else                                    // Person타입으로 형변환이 필요하다.
            return false;       // 타입이 Person이 아니면 값을 비교할 필요도 없다.
    }

    Person(long id) {
        this.id = id;
    }
}

class EqualsEx2 {
    public static void main(String[] args) {
        Person p1 = new Person(8011081111222L);
        Person p2 = new Person(8011081111222L);

        if (p1 == p2)
            System.out.println("p1과 p2는 같은 사람입니다.");
        else
            System.out.println("p1과 p2는 다른 사람입니다.");

        if (p1.equals(p2))
            System.out.println("p1과 p2는 같은 사람입니다.");
        else
            System.out.println("p1과 p2는 다른 사람입니다.");
    }
}
실행결과

p1과 p2는 다른 사람입니다.
p1과 p2는 같은 사람입니다.

 

 equals메서드가 Person인스턴스의 주소값이 아닌 멤버변수 id의 값을 비교하기 위해 equals메서드를 오버라이딩 했다. 서로 다른 인스턴스일지라도 같은 id를 가지고 있다면 equals메서드로 true결과를 얻을 수 있다.

 

 String클래스 역시 오버라이딩을 통해서 String인스턴스가 갖는 문자열 값을 비교하도록 되어있다. 때문에 같은 내용의 문자열을 갖는 두 String인스턴스에 equals메서드를 사용하면 항상 true값을 얻는 것이다.

 

 String클래스뿐만 아니라, Data, File, wrapper클래스의 equals메서드도 주소값이 아니라 내용을 비교하도록 오버라이딩되어 있다.

 

hashCode( )

 이 메서드는 해싱(hashing)기법에 사용되는 '해시함수(hash function)'을 구현한 것이다. 해시함수는 찾고자 하는 값을 입력하면, 그 값이 저장된 위치를 알려주는 해시코드(hash code)를 반환한다.

 

 클래스의 인스턴스변수 값으로 객체의 같고 다름을 판단해야 하는 경우라면 equals메서드뿐 아니라 hashCode메서드도 적절히 오버라이딩해야 한다. 같은 객체라면 hashCode메서드를 호출했을 때 해시코드도 같아야 하기 때문이다.

 

예제/HashCodeEx1.java

public class HashCodeEx1 {
    public static void main(String[] args) {
        String str1 = new String("abc");
        String str2 = new String("abc");

        System.out.println(str1.equals(str2));
        System.out.println(str1.hashCode());
        System.out.println(str2.hashCode());
        System.out.println(System.identityHashCode(str1));
        System.out.println(System.identityHashCode(str2));
    }
}
실행결과

true
96354
96354
460141958
1163157884

 

 String클래스에서는 문자열의 내용이 같으면 동일한 해시코드를 반환하도록 hashCode메서드에서 오버라이딩이 되어 있기 때문에 항상 동일한 해시코드값을 얻는다.

 

 반면에 System.identityHashCode(Object x)는 Object클래스의 hashCode메서드처럼 객체의 주소값으로 해시코드를 생성하기 때문에 모든 객체가 항상 다른 해시코드값을 반환한다.

 

toString( )

이 메서드는 인스턴스에 대한 정보를 문자열(String)로 제공한다.

 

public String toString( ) {

         return getClass( ).getName( ) + "@" + Integer.toHexString(hashCode( )) ;

}

 

 클래스를 작성할 때 toString( )을 오버라이딩하지 않으면 위와 같은 내용이 그대로 사용될 것이다. 즉, toString( )을 호출하면 클래스이름에 16진수의 해시코드를 얻게 된다.

 

서로 다른 인스턴스에 대해 toString( )을 호출하면 클래스의 이름은 같아도 해시코드값이 다르다.

 

예제/CardToString2.java

public class CardToString2 {
    public static void main(String[] args) {
        Card c1 = new Card();
        Card c2 = new Card("HEART", 10);
        System.out.println(c1.toString());
        System.out.println(c2.toString());
    }
}

class Card {
    String kind;
    int number;

    Card() {
        this("SPADE", 1);
    }

    Card(String kind, int number) {
        this.kind = kind;
        this.number = number;
    }

    public String toString() {		// Object클래스에서 toString( ) 접근제어자가 public이므로
        return "kind : " + kind + ", number : " + number;   // Card인스턴스의 kind와 number를
    }                                                       // 문자열로 반환
}
실행결과

kind : SPADE, number : 1
kind : HEART, number : 10

 

 Card인스턴스의 toString( )을 호출하면 인스턴스가 갖고 있는 인스턴스변수 kind와 number값을 문자열로 변환하여 반환하도록 오버라이딩했다.

 

 

 

 

출처 | Java의 정석 (남궁 성)

728x90