오늘의하루

[JAVA] Object Class 1편 equals hashCode toString clone 메서드 본문

JAVA

[JAVA] Object Class 1편 equals hashCode toString clone 메서드

오늘의하루_master 2022. 8. 4. 12:02

1. Object Class

Object는 모든 클래스의 최고 조상으로 11개의 메서드를 가지고 있습니다.

  1. protected Object clone( ) : 객체 자신의 복사본을 반환한다.
    • 오버 라이딩을 통해 접근제어자를 public으로 바꿔줘야 한다.
  2. public boolean equals(Object obj) : 객체 자신과 객체 obj가 같은 객체인지 알려준다.
    • 참조 변수에 저장된 주소를 비교한다.
    • 오버 라이딩을 통해 주소가 아닌 멤버 비교도 할 수 있다.
    • equals 메서드를 오버 라이딩하면 hashCode 메서드도 오버 라이딩해줘야 한다.
      • (중요) equals 메서드의 결과가 true이면 두 객체의 해시 코드는 같아야 하기 때문입니다.
  3. protected void finalize( ) : (거의 사용되지 않음) 객체 소멸 시 가비지 컬렉터에 의해 자동 호출된다.
  4. public Class getClass( ) : 객체 자신의 클래스 정보(설계도 정보)를 담고 있는 class 인스턴스를 반환한다.
    • class명 앞글자가 대문자이면 클래스 정보를 담기 위한 클래스이다.
    • getClass를 통해 얻는 것으로 객체 생성 및 객체 정보에 대해 알 수 있다.
      • 소스파일을 컴파일하면 *. class 파일이 생성된다.
      • *. class 파일을 실행하면 해당 파일명의 객체가 생성되는데 이게 설계도이다.
  5. public int hashCode( ) : 객체 자신의 해시 코드를 반환한다.
    • 객체의 해시 코드(정수 값)를 반환하는 메서드이다.
    • Object 클래스의 hashCode 메서드는 객체의 주소를 int로 변환해서 반환한다.
    • equals 메서드를 오버 라이딩하면 hashCode 메서드도 오버 라이딩해줘야 한다.
      • (중요) equals 메서드의 결과가 true이면 두 객체의 해시 코드는 같아야 하기 때문이다.
      • public int hashCode( ){return Object.hash(가변 인자);}
        • 가변 인자에는 매개변수를 1개만 넣어도 되고 100개를 넣어도 상관없습니다.
  6. public String toString( ) : 객체 자신의 정보를 문자열로 반환한다.
    1. 객체를 문자열(String)로 변환하기 위한 메서드
    2. 객체를 toString 메서드를 사용해서 출력하면 "클래스 이름 + @ + 주소 값을 int형으로 변환한 값"이 나온다.
  7. public void notify( ) : 객체 자신을 사용하려고 기다리는 스레드를 하나만 깨운다.
  8. public void notifyAll( ) : 객체 자신을 사용하려고 기다리는 모든 스레드를 깨운다.
  9. public void wait( )
  10. public void wait(long timeout)
  11. public void wait(long timeout, int nanos)
    • 9~11번 메서드의 대한 설명
      • 다른 스레드가 notify( )나 notifyAll( )을 호출할 때까지 현재 스레드를 무한히 또는 지정한 시간(timeout은 천분의 1초, nanos는 10^9분의 1초) 동안 기다리게 한다.

1-1. public boolean equals(Object obj)

  • Object클래스에 정의된 equals 메서드는 참조 변수 값(객체의 주소)을 비교한다.
  • equals 메서드를 오버 라이딩해서 인스턴스 변수의 값을 비교하도록 바꿀 수 있습니다.
class Person {
    long id;
    
    public boolean equals(Object obj){ // equals 오버라이딩
        if(obj != null && obj instanceof Person){
            return id == ((Person)obj).id;
        }else{
            return false;
        }
    }
    Person(long x){
        id = x;
    }
}

class Person2 {
    long id;

    Person2(long x){
        id = x;
    }
}

Person p1 = new Person(100L);
Person p2 = new Person(100L);
// 오버라이딩을 통해 인스턴스 변수를 비교하게 바꾸었기 때문에 true가 반환된다.
System.out.println(p1.equals(p2)); // true
// == 연산자는 주소값을 비교한다.
// 서로 다른 객체를 만들었기 때문에 주소값이 같을 수 없다.
System.out.println(p1 == p2); // false
        
Person2 p3 = new Person2(100L);
Person2 p4 = new Person2(100L);
// 오버라이딩 없이 euqals 메서드를 사용하면 주소값을 비교한다.
System.out.println(p3.equals(p4)); // fasle

 

1-2. public int hashCode( )

  • 객체의 해시 코드(int타입의 정수)를 반환하는 메서드
    • 다량의 데이터를 저장 및 검색하는 해싱 기법에 사용된다.
  • Object클래스의 hashCode( )는 객체의 내부 주소를 정수로 변환해서 반환한다.
  • equals 메서드를 오버 라이딩하면 hashCode 메서드도 같이 오버 라이딩해야 한다.
    • equals 메서드의 결과가 true인 두 객체의 hashCode는 같아야 하기 때문이다.
  • System.identityHashCode(Object obj)는 내부 주소를 정수로 변환해서 반환한다.
    • 오버 라이딩 불가
// ⭐equals와 hashCode를 오버라이딩 O
T t1 = new T(1);    
T t2 = new T(1);
System.out.println(t1.equals(t2)); // true
System.out.println(t1.hashCode()); // 32
System.out.println(t2.hashCode()); // 32
        
// ⭐equals와 hashCode를 오버라이딩 X
TT t3 = new TT(1);
TT t4 = new TT(1);
System.out.println(t3.equals(t4)); // false
System.out.println(t3.hashCode()); // 358699161
System.out.println(t4.hashCode()); // 517938326
        
// ⭐String 클래스는 아직 안배웠지만 다르다.
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1.equals(str2)); // true
System.out.println(str1.hashCode()); // 96354
System.out.println(str2.hashCode()); // 96354

class T{
    int id;
    
    public boolean equals(Object obj){ // equals 오버라이딩
        if(obj instanceof T){
            return id == ((T)obj).id;
        }else {
            return false;
        }
    }
    
    public int hashCode(){ // hashCode 오버라이딩
        return Objects.hash(id);
    }
    
    T(int x){
        id = x;
    }
}

class TT{
    int id;
    TT(int x){
        id = x;
    }
}

Objects 클래스는 객체와 관련된 유용한 메서드를 제공하는 유틸 클래스이다.

  • String 클래스는 자체적으로 equals는 주소 값이 아닌 내용을 비교하게끔 오버 라이딩되어있다.
  • String 클래스는 자체적으로 hashCode를 주소 값이 아닌 내용을 정수형으로 변환해서 반환하게 오버 라이딩되어있다.

1-3. toString( )

  • 객체의 정보를 문자열로 제공할 목적으로 정의된 메서드
public String toString(){
    return getclass().getName() + "@" + Integer.toHexString(hashCode());
}
  • 오버 라이딩을 통해 얼마든지 내용을 바꿀 수 있다.
Card c1 = new Card();
Card c2 = new Card();
System.out.println(c1.toString()); // Card@1b701da1
System.out.println(c2.toString()); // Card@1edf1c96
        
Card2 c3 = new Card2();
Card2 c4 = new Card2();
System.out.println(c3.toString()); // kind = Diamonds, number1
System.out.println(c4.toString()); // kind = Diamonds, number1

// 일반
class Card{
    String kind;
    int number;
    
    Card(){
        this("SPADE", 1);
    }
    Card(String kind, int number){
        this.kind = kind;
        this.number = number;
    }
}
// 오버라이딩
class Card2{
    String kind;
    int number;
    
    public String toString(){ // toString() 오버라이딩
        return "kind = " + kind + ", number" + number;
    }
    
    Card2(){
        this("Diamonds", 1);
    }
    Card2(String kind, int number){
        this.kind = kind;
        this.number = number;
    }
}

1-4. protected Object clone( )

  • 객체 자신을 복제해서 새로운 객체를 생성하는 메서드
  • Cloneable 인터페이스를 구현한 클래스의 인스턴스만 복제할 수 있다.
  • Object 클래스에 정의된 clone 메서드는 인스턴스 변수의 값만을 복제한다.
  • 인스턴스 변수가 참 조형일 때, 참조하는 객체도 복제되게 오버 라이딩해야 한다.
// Cloneable인터페이스를 구현한 클래스만 clone()을 호출할 수 있다.
// 구현하지 않고 clone()을 호출하면 예외가 발생한다.
class point implements Cloneable{
    int x;
    int y;
    point(int x, int y){
        this.x = x;
        this.y = y;
    }
    public String toString(){
        return "x = " + x + ", y = " + y;
    }
    public Object clone(){
        Object obj = null;
        try{
            obj = super.clone(); // clone메서드에는 CloneNotSupportedException이 선언되어 있기떄문에 예외처리를 해줘야한다.
        }catch(CloneNotSupportedException e){}
        return obj;
    }
}

point original = new point(1,2);
point copy = null;
// clone()의 리턴값이 Object 타입이기 때문에 형변화을 해줘야한다.
// 자식타입 = 부모타입 다형성이 성립되지 않기 때문이다.
copy = (point)original.clone();

// 인스턴스 변수와 메서드까지 복사해온다.
System.out.println(copy.x); // 1
System.out.println(copy.y); // 2
System.out.println(copy.toString()); // x = 1, y = 2
        
// copy객체와 original객체는 서로 다른 객체이다.
System.out.println(copy.hashCode()); // 1627800613
System.out.println(original.hashCode()); // 2065530879
Comments