[Java] Class Object

Java

(Update : 2017-09-17)

Language :

java.lang 패키지

자바프로그래밍에 가장 기본이 되는 클래스들을 포함하고 있다.

Class Object

모든 클래스의 최고 조상

Object 클래스의 멤버들은 모든 클래스에서 바로 사용 가능하다.

멤버 변수는 없고 오직 11개의 메서드(모든 인스턴스가 가져야 할 기본적인 것들)만 가지고 있다.

protected Object clone()

객체 자신을 복사하여 새로운 인스턴스를 생성한다.

단순히 인스턴스 변수의 값만 복사하기 때문에 참조 변수 타입의 인스턴스 변수가 정의되어 있는 클래스는 인스턴스가 완전히 복제되지 않는다.

Clonealbe 인터페이스를 구현한 클래스에서만 clone()을 호출할 수 있다. (인스턴스의 데이터 보호)

오버라이딩하면서 접근 제어자를 public으로 변경해야 상속관계가 없는 다른 클래스에서 clone()을 호출할 수 있다.

조상 클래스의 clone()을 호출하는 코드가 포함된 try-catch문을 작성한다. ← 반드시 예외 처리 해야 한다.

public class Test {
    public static void main(String[] args) {
        ObjTest original = new ObjTest(10);
        ObjTest copy = (ObjTest) original.clone();

        System.out.println(copy.x);       // 10
    }
}

class ObjTest implements Cloneable {
    int x;
    ObjTest(int x) { this.x = x; }

    @Override
    protected Object clone() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
        }
        return obj;
    }
}
  • 공변 반환타입 Covariant Return Type

     JDK1.5부터 오버라이딩할 때 조상 메서드의 반환 타입을 자손 클래스의 타입으로 변경하는 것을 허용한다.

     clone() 호출 시 자손 객체의 타입으로 형변환하는 번거로움이 줄어든다.

public class Test {
    public static void main(String[] args) {
        ObjTest original = new ObjTest(10);
        ObjTest copy = original.clone();

        System.out.println(copy.x);          // 10
    }
}

class ObjTest implements Cloneable {
    int x;
    ObjTest(int x) { this.x = x; }

    @Override
    protected ObjTest clone() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
        }
        return (ObjTest) obj;
    }
}
  • 배열

     배열도 객체이기 때문에 Object 클래스를 상속받으며, Cloneable 인터페이스와 Serializable 인터페이스가 구현되어 있다.

     System.arraycopy()를 이용하는 것과 같은 결과를 얻는다.

  • 얕은 복사 Shallow Copy

      기본형 배열과 달리 객체 배열은 clone()을 사용하면 원본과 복사본이 같은 객체를 공유한다.

     원본의 변경이 복사본에 영향을 주므로 완전한 복제라고 보기 어렵다.

  • 깊은 복사 Deep Copy

     원본이 참조하고 있는 객체까지 복사한다.

     원본과 복사본이 서로 다른 객체를 참조하기 때문에 원본의 변경이 복사본에 영향을 미치지 않는다.

public boolean equals(Object obj)

객체 자신과 객체 obj가 같은 지 참조변수의 값(주소값)으로 판단한다.

public class Test {
    public static void main(String[] args) {
        ObjTest t1 = new ObjTest(10);
        ObjTest t2 = new ObjTest(10);

        System.out.println(t1.equals(t2));  // false

        t1 = t2;

        System.out.println(t1.equals(t2));  // true
    }
}

class ObjTest {
    int x;
    
    ObjTest(int x) {
        this.x = x;
    }
}

주소가 아닌 객체에 저장된 내용을 비교하고 싶을 땐 equals 메서드를 오버라이딩 한다.

ex) String, Date, File, wrapper 클래스(Integer, Double 등)

public class Test {
    public static void main(String[] args) {
        ObjTest t1 = new ObjTest(10);
        ObjTest t2 = new ObjTest(10);

        System.out.println(t1.equals(t2));  // true

        t1 = t2;

        System.out.println(t1.equals(t2));  // true
    }
}

class ObjTest {
    int x;
    
    ObjTest(int x) {
        this.x = x;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof ObjTest) {
            return x == ((ObjTest) obj).x;
        } else {
            return false;
        }
    }
}

protected void finalize()

객체가 소멸될 때 가비지 컬렉터에 의해 자동 호출된다.

public Class getClass()

객체 자신의 클래스 정보를 담고 있는 Class 인스턴스를 반환한다.

  • Class 객체

     이름이 'Class'인 클래스의 객체.

     클래스당 단 1개만 존재하며, 클래스의 모든 정보를 담고 있다.

     클래스 로더에 의해 메모리에 올라갈 때 자동적으로 생성된다.

  • 클래스 로더 ClassLoader

     실행 시에 필요한 클래스를 동적으로 메모리에 로드하는 역할

     파일 형태로 저장되어 있는 클래스를 읽어서 Class클래스에 정의된 형식으로 변환한다.

  • Class 객체 얻기

     클래스의 정보가 필요할 때, Class 객체에 대한 참조를 얻어와야 한다.

Class co = new Test().getClass();   // 생성된 객체로 얻기

     Class 객체를 통해 객체를 생성하고 메서드를 호출하는 등 보다 동적인 코드를 작성할 수 있다.

try {
    Test t = Test.class.newInstance();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

newInstance()는 InstantiationException이 발생할 수 있다.

public int hashCode()

객체의 주소값을 이용해서 해시코드를 만들어 반환한다.

해싱(Hashing) 기법에 사용되는 해시함수(Hash Function)를 구현한 것이다.

서로 다른 객체는 같은 해시코드를 가질 수 없다.

public class Test {
    public static void main(String[] args) {
        ObjTest t1 = new ObjTest(10);
        ObjTest t2 = new ObjTest(10);

        System.out.println(t1.hashCode());                // 366712642
        System.out.println(t2.hashCode());                // 1829164700
    }
}

String 클래스는 문자열의 내용이 같으면 동일한 해시코드를 반환하도록 오버라이딩되어 있다.

반면 System.identityHashCode(Object x)는 모든 객체에 대해 항상 다른 해시코드 값을 반환할 것을 보장한다.

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

        System.out.println(str1.hashCode());                // 65
        System.out.println(str2.hashCode());                // 65
        System.out.println(System.identityHashCode(str1));  // 366712642
        System.out.println(System.identityHashCode(str2));  // 1829164700
    }
}

public String toString()

객체 자신의 정보를 문자열로 반환한다.

인스턴스나 클래스에 대한 정보 또는 인스턴스 변수들의 값을 문자열로 변환하여 반환하도록 오버라이딩되는 것이 보통이다.

public class Test {
    public static void main(String[] args) {
        ObjTest t = new ObjTest(1);
        System.out.println(t.toString());     // x : 1
    }
}

class ObjTest {
    int x;
    
    ObjTest(int x) {
        this.x = x;
    }
    
    @Override
    public String toString() {      
        return "x : " + x; 
    }
}

Object 클래스에 정의된 메서드를 호출하면 클래스 이름에 16진수의 해시코드를 얻게 된다.

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public class Test {
    public static void main(String[] args) {
        ObjTest t1 = new ObjTest(1);
        ObjTest t2 = new ObjTest(1);

        System.out.println(t1.toString());     // ObjTest@15db9742
        System.out.println(t2.toString());     // ObjTest@6d06d69c
    }
}

public void notify()

객체 자신을 사용하려고 기다리는 쓰레드를 하나만 깨운다.

public void notifyAll()

객체 자신을 사용하려고 기다리는 모든 쓰레드를 깨운다.

public void wait(), wait(long timeout), wait(long timeout, int nanos)

다른 쓰레드가 notify()나 notifyAll()을 호출할 때까지 현재 쓰레드를 무한히 또는 지정된 시간(timeout, nanos)동안 기다리게 한다.

(timeout: 천 분의 1초. nanos: 10의 9승분의 1호)

Object API

참고 서적: 자바의 정석 3판

민갤

Back-End Developer

백엔드 개발자입니다.