본문 바로가기

프로그래밍 공부/Java

Java - Java API 클래스 : Object 클래스

Object 클래스 설명
java.lang Java에서 가장 기본적인 동작을 수행하는 클래스 집합, impot문을 사용하지 않아도 사용이 가능
java.lang.Object 모든 Java 클래스의 최고 조상 클래스, 모든 Java 클래스는 Object 클래스의 메서드 사용이 가능
toString() 해당 인스턴스에 대한 정보를 문자열로 반환, 반환값은 클래스명과 함께 구분자로 @가 사용
equals() 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교해 결과를 boolean값으로 반환
clone() 해당 인스턴스를 복제해 새로운 인스턴스를 생성하고 반환, 단순 필드값만을 복사

java.lang package

java.lang 패키지는 Java에서 가장 기본적인 동작을 수행하는 클래스들의 집합이며, java.lang 패키지의 클래스들은 import문을 사용하지 않아도 클래스 이름만으로 바로 사용할 수 있도록 하고 있다.

java.lang.Object class

java.lang 패키지 중에서 가장 많이 사용되는 클래스가 Object 클래스이다. 이것은 모든 Java 클래스의 최고 상위의 클래스가 되며, Java의 모든 클래스는 Object 클래스의 모든 메서드를 바로 사용할 수 있다. 이런 Object 클래스는 필드를 가지지 않으며, 총 11개의 메서드만으로 구성되어 있다.

toString() method

toString() 메서드는 해당 인스턴스에 대한 정보를 문자열로 리턴한다. 이때 리턴되는 문자열은 클래스명과 함께 구분자로 @가 사용되고, 그 뒤로 16진수 해시 코드(Hash code)가 추가된다. 16진수 해시 코드 값은 인스턴스의 주소를 가리키는 값으로, 인스턴스마다 모두 다르게 리턴된다.

1
2
3
4
5
6
7
8
9
10
// toString() 메서드
Car car01 = new Car();
Car car02 = new Car();
 
System.out.println(car01.toString());
System.out.println(car02.toString());
 
실행결과
Car@15db9742
Car@6d06d69c
cs

Java에서 toString() 메서드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재정의되어 있다.

equals() method

equals() 메서드는 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교해, 그 결과를 리턴한다. 이때 참조 변수가 가리키는 값을 비교하므로, 서로 다른 두 객체는 언제나 boolean 값인 false를 리턴하며 서로 같은 두 객체는 반대인 true를 리턴한다.

1
2
3
4
5
6
7
8
9
10
11
12
// equal() 메서드
Car car01 = new Car();
Car car02 = new Car();
 
System.out.println(car01.equal(car02));
 
car01 = car02;
System.out.println(car01.equal(car02));
 
실행결과
false
true
cs

Java에서 equals() 메서드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재정되어 있다.

clone() method

clone() 메서드는 해당 인스턴스를 복제하고 새로운 인스턴스를 생성해 반환한다. 하지만 Object 클래스의 clone() 메서드는 단지 필드의 값만을 복사하므로, 필드의 값이 배열이나 인스턴스면 제대로 복제할 수 없다. 따라서 해당 클래스에서 clone() 메서드를 오버라이딩해, 복제가 제대로 이루어지도록 재정의해야 한다.

clone() 메서드는 데이터의 보호를 이유로 Cloneable 인터페이스를 구현한 클래스의 인스턴스만이 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// clone() 메서드
 
import java.util.*;
 
class Car implements Cloneable {
    private String modelName;
①  private ArrayList<String> owners = new ArrayList<String>();
 
    public String getModelName(){
        return this.modelName;            // modelName의 값을 리턴
    }
    public void setModelName(String modelName){
        this.modelName = modelName;        // modelName의 값을 설정
    }
    
    public ArrayList getOwners(){
        return this.owners;                // owner의 값을 리턴
    }
    public void setOwners(String ownerName){
        this.owners.add(ownerName);        // owner의 값을 설정
    }
 
    public Object clone(){
        try{
②          Car clonedCar = (Car)super.clone();
③          // clonedCar.owner = (ArrayList)owners.clone();
            return clonedCar;
④      }catch(CloneNotSupportedException e){
            e.printStackTrace();
            return null;
        }
    }
}
 
public class Main{
    public static void main(String[] args){
⑤      Car car01 = new Car();
        car01.setModelName("아반떼");
        car01.setOwners("김철수");
⑥      System.out.println("Car01 : " + car01.getModelName() + ", " + car01.getOwners() + "\n");
 
⑦      Car car02 = (Car)car01.clone();
⑧      car02.setOwners("박은혜");
⑨      System.out.println("Car01 : " + car01.getModelName() + ", " + car01.getOwners());
 
⑩      System.out.println("Car02 : " + car02.getModelName() + ", " + car02.getOwners());
    }
}
cs

②번(25행) 라인에서는 부모 클래스의 clone() 메서드를 호출해 clone() 메서드를 오버라이딩하고 있다. ⑤번(37행) 라인에서는 Car 클래스의 인스턴스인 car01을 생성하고, ⑦번(42행) 라인에서는 오버라이딩한 clone() 메서드를 호출해 복제를 수행하고 있다.

하지만 ②번(25행) 라인처럼 clone() 메서드를 재정의하면 필드 값이 ①번(7행) 라인처럼 인스턴스일 때는 제대로된 복제를 수행할 수 없다. ⑧번(43행) 라인에서는 복제된 인스턴스인 car02의 owners 필드에 새로운 값을 하나 추가한다. 하지만 ⑨번(44행) 라인의 실행 결과를 보면, ⑦번(42행) 라인의 결과와는 달리 원본 인스턴스인 car01의 owner 필드에도 새로운 값이 추가되었음을 확인할 수 있다. 

이처럼 단순히 부모 클래스의 clone() 메서드를 호출해 clone() 메서드를 재정의 하면, 배열이나 인스턴스인 필드는 복제되는 것이 아닌 해당 배열이나 인스턴스를 가리키는 주소값만이 복제되는 것이다.

따라서 정확한 복제를 위해서는 ③번(26행) 라인처럼 배열이나 인스턴스인 필드에 대해서는 별도로 clone() 메서드를 구현하여 호출해야 한다.

그 외 Object 메서드

메서드명 설명
protected Object clone() 해당 객체의 복제본을 생성하여 리턴
boolean equals(Object obj) 해당 객체와 전달받은 객체가 같은지 여부를 판단하여 리턴
protected void finalize() 해당 객체를 더는 아무도 참조하지 않아 가비지 컬렉터가 객체의 리소스 정리를 위해 호출
Class<T>getClass() 해당 객체의 클래스 타입을 리턴
int hashCode() 해당 객체의 해시 코드값을 리턴
void notify() 해당 객체의 대기(wait)하고 있는 하나의 스레드를 다시 실행할 때 호출
void notifyAll() 해당 객체의 대기(wait)하고 있는 모든 스레드를 다시 실행할 때 호출
String toString() 해당 객체의 정보를 문자열로 리턴
void wait() 해당 객체의 다른 스레드가 notify()나 notifyAll() 메서드를 실행할 때까지 현재 스테드를 일시적으로 대기(wait)시킬 때 호출
void wait(long timeout) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메서드를 실행하거나 전달받은 시간이 지날 때까지 현재 스테드를 일시적으로 대기(wait)시킬 때 호출
void wait(long timeout, int nanos) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메서드를 실행하거나 전달받은 시간이 지나거나 다른 스레드가 현재 스레드를 인터럽트(Interrupt)할 때까지 현재 스테드를 일시적으로 대기(wait)시킬 때 호출