Object 클래스의 메소드들은 어떻게 구성되어 있을까?
----------------------------------------------------------------------------------------------------------------
Java의 lang 채패키지는 Java 프로그래밍에 필요한 가장 기본적인 클래스들이 모여있는 패키지 이다.
lang패키지에 포함되는 클래스는 따로 import하지 않아도 최상위 클래스가 된다.
Object Class란 ??
자바에서 모든 클래스는 사실 Object를 암시적으로 상속받고 있는 것이다. 그런 점에서 Object는 모든 클래스의 조상이라고
할 수 있다. 그 이유는 모든 클래스가 공통으로 포함하고 있어야 하는 기능을 제공하기 위해서다.
그렇기 때문에 Object클래스의 맴버들은 모든 클래스에서 바로 사용이가능며 맴버 변수는 존재하지않으며 메소드만 가지고 있다.
registerNatives
Object 클래스를 들어가보면 가장 윗부분에 registerNatives 라는 것이 나온다.
이것은 (OpenJDK의 구현에서) Object 클래스의 네이티브 함수를 등록하는 코드이다.
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
hashCode
public native int hashCode();
hashCode 메소드는 객체의 해시코드 값을 리턴한다.
hash는 hashTable 이라는 배열을 이용해 데이터를 저장하고 주소값을 저장하기때문에 많은양의 데이터를 저장하고 빠른 검색이 가능하다.
각 객체의 hashCode는 유일하며 같은 값을 가질 수 없다.
객체가 변경이 되더라도 hashCode는 변하지 않는다.
public class Main {
public int number = 1;
public static void main(String[] args) {
Main a = new Main();
Main b = new Main();
System.out.println("객체 변경전 a hashCode값 -> "+a.hashCode());
System.out.println("객체 변경전 b hashCode값 -> "+b.hashCode());
b.number = 2;
System.out.println("객체 변경후 b hashCode값 -> "+b.hashCode());
}
}
equals
public boolean equals(Object obj) {
return (this == obj);
}
equals 메소드는 이 객체가 다른 객체와 같은지 아닌지를 나타낸다.
즉, 주소값을 비교한다는 것이다.
두개의 레퍼런스가 동일한 인스턴스를 가르키고 있다면 true를 아니라면 false를 리턴한다.
Main a = new Main();
Main b = a;
//Main b = new Main();
System.out.println(a.equals(b));
Main a = new Main();
//Main b = a;
Main b = new Main();
System.out.println(a.equals(b));
단, String 클래스는 equals로 비교할때는 주소값으로 비교를 하는것이 아니라 객체 내용이 같은지 아닌지를 비교한다.
이 이유는 String 클래스는 내부적으로 equals함수를 오버라이딩 하여 아래와 같이 내용이 같으면 true를 반환하도록 재정의가 되어있기 때문이다.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
clone
protected native Object clone() throws CloneNotSupportedException;
clone 메서드는 자신을 복사하여 새로운 인스턴스를 생성하는 역할을 한다.
clone 메서드를 사용하기 위해서는 Cloneable인터페이스를 꼭 구현해야 하며 안하면 예외가 발생한다.
주의 해야 할 점은 단순히 멤버 변수의 값을 복사하기 때문에 배열이나 인스턴스가 맴버로 정의되어 있는 클래스는 완전한 복사가 이루어지지 않는다.
그러므로 클래스 내부에 clone() 함수를 오버라이딩하여 완전한 복사가 되도록 재정의 해주어야 한다.
public Object clone() {
Object obj=null;
try {
obj = super.clone();
} catch(CloneNotSupportedException e) {}
return (Main)obj;
}
toString
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString 메서드는 객체를 String 표현을 리턴한다.
Object 클래스의 toString 메소드는 인스턴스 객체의 클래스 이름, ‘@’기호, 그리고 16진수로 표현된 객체의 해시 코드로 구성된 문자열을 리턴한다.
즉, 객체를 “텍스트로 표현”한 문자열을 리턴한다.
결과는 간결하면서도 충분한 정보를 담고 있어야 하며 Object의 모든 서브클래스에 대해 이 메소드의 오버라이드를 권장한다.
notify , notifyAll , wait
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
이 3가지의 메서드는 Thread를 제어할 때 필요한 메서드 들이다.
wait - 갖고 있던 고유락을 해제하고 스레드를 잠들게 한다.
notify - 잠들어 있던 스레드 중 임의로 하나를 골라 깨운다.
notifyAll - 호출로 잠들어 있던 스레드를 모두 깨운다.
이 3가지의 메서드들은 호출하는 스레드가 반드시 고유 락을 갖고 있어야 한다. 다시 말해, synchronized 블록 내에서 호출되어야 한다.
wait() 메서드를 호출하면 락을 해제하고, 스레드는 잠이 든다. 누군가 깨워줄 때 까지 wait()은 리턴되지 않는다.
notify(), notifyAll() 메서드는 둘 다 wait()으로 잠든 메서드를 깨운다. 둘의 차이는 잠든 스레드 하나만 깨우냐, 모두 깨우냐의 차이이다.
notify() 메서드는 어느 스레드를 깨울지 선택할 수 없기 때문에 제어가 어렵다. 그래서 보통은 notifyAll()을 사용한다. notifyAll()이 모든 스레드를 깨
우긴 하지만 이 메서드를 호출한다고 해서 잠들어 있던 모든 스레드가 동시에 동작하는 것은 아니다.
finalize
protected void finalize() throws Throwable { }
자바의 메모리 해제는 Garbage Collector(이하 GC)에 의해 수행됩니다. finalize()는 GC에 의해 호출된다.
파이널 라이저의 주요 목적은 오브젝트가 메모리에서 제거되기 전에 오브젝트가 사용하는 자원을 해제하는 것이다.
참조
http://happinessoncode.com/2017/10/05/java-object-wait-and-notify/
https://www.baeldung.com/java-finalize
http://whatisthenext.tistory.com/62
'java' 카테고리의 다른 글
클래스 , 오브젝트 , 인스턴스의 차이 (0) | 2018.11.24 |
---|---|
final, static 키워드란? (0) | 2018.11.23 |