코린이의 소소한 공부노트

Object 클래스와 메서드 본문

Java

Object 클래스와 메서드

무지맘 2022. 6. 16. 13:19

Object 클래스

1. 모든 클래스의 최고 조상 클래스이다.

2. iv 없이 메서드만 11개 있다.

Object 클래스의 메서드 11개

  - finalize(): 생성자와 반대 개념의 메서드. 메모리 부족으로 인해 객체를 없애야 할 때, finalize()에 수행되어야 할 코드가 있다면 이걸 실행하느라 메모리 정리하는 데 시간을 더 쓸 수 있으므로 가급적이면 사용하지 않는 메서드.

  - getClass(): Class 클래스는 클래스 정보(조상 클래스, iv 개수, 생성자 등)를 담기 위한 클래스. getClass()를 이용하면 메서드를 호출한 클래스의 정보가 담긴 Class 객체(인스턴스)를 반환.

  - notify(), notifyAll(), wait(): 쓰레드와 관련된 메서드.

  - protected 메서드인 clone()과 finalize()는 public으로 오버라이딩해야 사용 가능.

 

11개의 메서드 중 3가지를 자세히 살펴보려 한다. 아래 코드는 메서드를 살펴보는데 도움을 줄 Card 클래스이다.

class Card{
    String pattern;	// 카드 무늬
    int number;		// 카드 번호
    
    Card(){		// 기본 생성자
        this("SPADE", 1);
    }
    
    Card(String p, int n){ // 생성자
        this.pattern = p;
        this.number = n;
    }
}

1. equals() 메서드

// Object 클래스
public boolean equals(Object obj){
	return this==obj;
}

 1) 객체 자신(this)과 주어진 객체(obj)를 비교한다.

 2) 같으면 true, 다르면 false를 반환한다.

 3) Object 클래스의 equals()는 객체의 주소(참조변수의 값)를 비교한다.

// main() 내부
Card c1 = new Card();
Card c2 = new Card();

System.out.println(c1.equals(c2)); // false
// c1이 this, c2가 obj

  - Card 클래스에 equals()가 오버라이딩되어있지 않으므로 main()에서 호출한 equals()는 Object 클래스의 것이다.

  - c1과 c2 객체가 다르므로 당연히 주소를 비교하면 false가 나온다. 하지만 둘 다 기본 생성자로 생성했기 때문에 pattern도 "SPADE"로 같고 number도 1로 같으므로 비교를 했을 때 같다고 나오는 게 일반적으로 생각했을 때 훨씬 자연스럽다. 이렇게 바꿔주려면 오버라이딩을 해야 한다.

// Card 클래스에 equals() 오버라이딩
public boolean equals(Object obj){ // 오버라이딩은 선언부 일치
    if(!(obj instanceof Card))
        return false;
    
    Card c = (Card)obj;
    return this.pattern == c.pattern && this.number == c.number;
}

// main() 내부
System.out.println(c1.equals(c2)); // true

  - Object 클래스에는 pattern, number라는 iv가 없다. 때문에 iv에 접근하려면 Card로 형변환을 해야 한다. 그래서 obj가 Card의 자손이 아니면 비교할 필요가 없으므로 false를 반환하게 하고, 자손이라면 value값을 비교하게 하면 우리가 생각하는 대로 오버라이딩이 된다.

  - 객체에는 cv와 iv가 있는데, cv는 객체가 공통으로 갖는(공유하는) 변수이고, iv는 객체마다 다른 변수이기 때문에 cv는 굳이 비교할 필요가 없다. 따라서 equals()를 오버라이딩할 때 iv를 비교하도록 해야 한다.

 

2. hashCode() 메서드

public class Object{
    // ...
    public native int hashCode();
    // ...

 1) 객체의 해시 코드를 반환하는 메서드다.

 2) 해시 코드 값은 정수이다.

 3) Object 클래스의 hashCode()는 객체의 주소를 int로 변환해서 반환한다

  - 여기서 native는 OS의 메서드라는 뜻으로, 보통 c언어로 작성되어있다.

  - OS의 메서드를 갖다 쓰는 것이기 때문에, 내용이 없다.

 4) 해시 코드는 객체마다 값이 다 달라서 객체의 지문이라고도 표현한다.

  - 해시 코드가 같다는 뜻은 주소가 같다는 뜻이기도 하다.

  - 주소를 이용한 메서드 equals()와 hashCode()의 경우, equals()를 주소가 아닌 iv를 이용하게끔 오버라이딩하면 hashCode()도 오버라이딩해야 한다.

  - equals()의 결과가 true인 두 객체의 해시 코드는 같다. 오버라이딩한 equals()의 결과가 true라는 것은 iv값이 같다는 것을 의미한다.

// main() 내부
System.out.println(c1.equals(c2)); // true
System.out.println(c1.hashCode()); // 604107971
System.out.println(c2.hashCode()); // 123961122

// hashCode()도 equals()처럼 오버라이딩 해야 한다.

// Card 클래스 내부
public int hashCode(){
    return Objects.hash(pattern, number); // java.util.Objects;
}

// 다시 main()으로 와서
System.out.println(c1.hashCode()); // -1842861219
System.out.println(c2.hashCode()); // -1842861219

  - hashCode() 오버라이딩에 쓰인 Objects 클래스는 객체와 관련된 유용한 메서드를 제공하는 유틸 클래스다.

 5) System.identityHashCode(Object obj)는 Object 클래스의 hashCode()와 동일하다.

System.out.println(System.identityHashCode(c1)); // 604107971
System.out.println(System.identityHashCode(c2)); // 123961122
// hashCode() 오버라이딩 전과 같은 결과

  - 32bit JVM은 주소 값이 int이고, 64bit JVM은 주소 값이 long이다.

  - 64bit의 경우 반으로 잘라 뒤 4byte만 해시 코드값으로 변환된다. 때문에 해시 코드값이 중복될 수 있는데, 워낙 많이 쓰이는 메서드라 메서드 수정을 하지 않고 그대로 사용한다.

 

3. toString() 메서드

public class Object{
    // ...
    public String toString(){
        return getClass().getName()+"@"+Integer.toHexString(hashCode());
    }
    // ...

 1) 객체를 문자열로 변환하기 위한 메서드다.

 2) getClass().getName() : 클래스의 이름을 반환해준다.

 3) "@": at. 위치라는 뜻으로 클래스의 이름과 해시 코드 값을 구분해준다.

 4) Integer.toHexString(hashCode()): 해시 코드 값을 16진수 문자열로 바꿔준다.

// main() 내부

// hashCode() 오버라이딩 전
System.out.println(c1.toString()); // Card@2401f4c3
System.out.println(c2.toString()); // Card@7637f22

// hashCode() 오버라이딩 후
System.out.println(c1.toString()); // Card@92282b5d
System.out.println(c2.toString()); // Card@92282b5d

// equals() 오버라이딩 여부는 실험결과 상관 없었다.

  - main()에서 Card 객체를 만들어서 toString()을 호출하면 위와 같이 클래스 이름과 주소의 16진수 값이 출력된다.

  - 객체는 iv의 집합이기 때문에 주소 값보다는 iv값을 출력하는 게 훨씬 유용하다. 그래서 보통 오버라이딩을 한다.

// Card 클래스에 추가
public String toString(){
    return "pattern=" + pattern + ", number=" + number;
}

// main() 내부
System.out.println(c1.toString()); // "pattern=SPADE, number=1"
System.out.println(c2.toString()); // "pattern=SPADE, number=1"

'Java' 카테고리의 다른 글

문자열의 결합과 변환  (0) 2022.08.18
String 클래스  (0) 2022.08.16
연결된 예외  (0) 2022.06.10
사용자 정의 예외 만들기, 예외 되던지기  (0) 2022.05.27
예외 처리 (2) - 메서드에 예외 선언하기, finally 블록  (0) 2022.05.26