경주장

6주차 과제: 상속 #6 (~02.29) - Object 클래스 본문

JAVA/whiteship_live-study

6주차 과제: 상속 #6 (~02.29) - Object 클래스

달리는치타 2022. 2. 23. 17:19

✔️ 학습할 것 (필수)

  • 자바 상속의 특징
  • 메소드 오버라이딩
  • final 키워드
  • super 키워드
  • 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)
  • 추상 클래스
  • Object 클래스

정리 해야지 해야지 하고 몇번 시도해보았지만 항상 미루게 되고 이해가 안되던 자바 개념인 Object 클래스를 좋은 기회로 정리할 수 있게 되었습니다. 이번주차의 다른 "학습할 것"들과 마찬가지로 오라클 자바 도큐먼트를 참고하여 정리하였습니다.


java.lang 패키지의 Object 클래스는 class hierachy tree의 최 상단에 위치합니다. 이번 섹션에서 다루고자하는 Object의 메소드는 아래와 같습니다.

메소드 선언부 description
protected Object clone() throws CloneNotSupportedException Creates and returns a copy of this object.
public boolean equals(Object obj) Indicates whether some other object is "equal to" this one
protected void finalize() throws Throwable Called by the garbage collector on an object when garbage collection determines that there are no more references to the object
public final Class getClass() Returns the runtime class of an object.
public int hashCode() Returns a hash code value for the object.
public String toString() Returns a string representation of the object.

Object 클래스의 notify, notifyAll 그리고 wait 메소드는 프로그램의 독립적인 쓰레드들간의 동기화와 관련된 역할을 하는 메소드입니다. 이번 장에서는 다루지 않겟습니다.


The clone() Method

클래스나 클래스의 부모중 한 녀석이 Cloneable 인터페이스를 구현하였다면 clone( ) 메소드를 통해 객체의 복사본을 만들 수 있습니다. Cloneable 인터페이스를 명시적으로 구현하는 이유는 클래스 설계자가 복제를 허용한다는 의도적인 표시를 하기 위해서입니다.

Clonable 인터페이스를 구현하지 않은 객체가 clone 메소드를 호출하면 _CloneNotSupportedException_이 발생합니다. clone의 기본구현 (Object 메소드의)은 꽤 잘 동작하지만 필드로 다른 클래스의 레퍼런스를 가지는 경우 문제가 생길 수 있습니다. 즉 두 객체가 한 레퍼런스를 참조하는 문제가 발생 할 수 있습니다. 문제를 방지하기 위해 clone 메소드를 사용하는 경우 직접 오버라이딩 해서 사용합시다. 

 

해당 문제를 재현하기 위해서 시도해 보았는데 잘 되지 않았습니다... 혹시 아시는 분은 알려주시면 감사하겠습니다.

The equals() Method

eqauls( ) 메소드는 두 객체의 "동등성"을 판별합니다. Object 클래스의 equals 구현은 "identity 연산자 (==연산자)"를 활용합니다. primitive data type들에 대해서는 == 비교로 equality와 같은 효과를 낼 수 있습니다. 하지만 레퍼런스 타입의 객체에서는 그렇지 않습니다.

앞서 언급하였듯이 Object 클래스의 equals 구현은 "identity 연산자 (==연산자)"를 활용합니다. 레퍼런스 타입에서 동일성은 동등성과 다른 개념입니다. 객체의 필드 값을 비교한 동등성을 알아내기 위해서는 객체의 equals 메서드를 오버라이드 하여 재정의 하여야합니다.

보통 인텔리제이, 이클립스 등의 IDE의 도움을 받으면 일반적인 많은 경우에 적용가능한 equals and hashcode를 쉽게 재정의 할 수 있습니다.

public class Users {
    private String username;
    private int age;
}

와 같은 클래스에 대해 인텔리제이는 아래와 같은 equals and hashcode를 간단하게 제공해 줍니다.

@Override
public boolean equals(Object o) {
    //같은 레퍼런스라면 true
    if (this == o) return true;

    //null이거나 class가 다른 경우 false
    if (o == null || getClass() != o.getClass()) return false;

    //casting을 하여 primitive 타입 필드에 대해서는 == 비교를
    //reference 타입 필드에 대해서는 Objects.equals()를 호출하여 모두 동등,동일한지 확인
    Users users = (Users) o;
    return age == users.age && Objects.equals(username, users.username);
}

@Override
public int hashCode() {
    // Objects.hash 에 필드 전달
    return Objects.hash(username, age);
}

The hashCode() Method

hashCode( ) 는 객체의 해시코드를 반환합니다. 해시코드는 해싱 알고리즘에 따라 생성된 int 값입니다.

Note !

  • equals( ) 메소드를 오버라이드 할때는 곡 hashCode( ) 메소드도 오버라이드 해야합니다.
    • If you override the equals() method, you change the way two objects are equated and Object's implementation of hashCode() is no longer valid. Therefore, if you override the equals() method, you must also override the hashCode() method as well.
  • 꼭 기억해 두시면 좋을것 같은 규칙
    • equals가 true라면 두 객체가 반환하는 hashcode 값은 같아야한다.
    • 반대는 성립하지 않는다. (hashcode가 같다고해서 equals가 true임을 보장할 수 없다.)
  • 컬렉션 프레임워크 - HashSet, HashMap, Hashtable이 객체의 동등성을 비교하는 방식

객체의 동등성 비교

 

 

The toString() Method

toString( ) 메소드는 객체의 String representation을 제공합니다. Object 클래스의 기본 toString( ) 구현은 아래와 같습니다.

public String toString() {
    // FQCN(Fully Qualified Class Name)@OxHashCode
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

 

//to String 결과 값 예시
//패키지명 포함 클래스명@해시코드
study.object.clone.CloneStudyV1$UserSubclass@30c7da1e

toString( ) 메소드는 디버깅에 매우 중요합니다. toString 메소드를 오버라이딩함으로써 디버깅시 클래스와 해시코드와 같은 의미 없는 값이 아닌 필드의 유효한 값을 눈으로 확인 할 수 있습니다.

 

The getClass() Method

Object  클래스에 선언된 getClass( ) 

public final native Class<?> getClass();

final 키워드를 통해 재정의를 막아 놓았다. 즉 override할 수 없다.

객체의 클래스정보를 담은 Class 객체를 반환한다. Class 객체로부터 클래스의 이름, 인터페이스, 어노테이션 포함여부 등의 다양한 정보를 얻을 수 있다.

 

The finalize() Method - 객체 소멸자

@Deprecated(since="9")
protected void finalize() throws Throwable { }

Garbage Collector가 호출하여 object를 메모리에서 release 하는 역할로써 사용하는 finalize 메소드이다. 오버라이드 하여 직접 호출 할 수도 있지만 deadlock, resourceleak과 같은 문제를 야기할 수 있기 때문에 Deprecated 되었다.