Object클래스
Object 변수는 모든 자바 클래스의 부모 클래스이다. 때문에 모든 클래스는 Object의 메서드를 사용할 수 있는데, 모든 클래스가 공통으로 포함하고 있어야 하는 기능을 제공하기 위해서 존재한다고 생각해도 무방하다.
String toString()
- 인스턴스에 대한 정보를 문자열로 반환한다. 해당 메소드는 기본적으로 각 API 클래스마다 자체적으로 오버 라이딩을 통해 재정의되어 있기 때문에 활용도가 높다.
- newObject.toString();
protected Object clone()
- 해당 인스턴스를 복제하여, 새로운 인스턴스를 생성해 반환한다. 하지만 필드의 값만을 복사하므로, 필드의 값이 배열이나 인스턴스면 제대로 복제할 수 없다. 따라서 클래스에서 Cloneable 인터페이스를 구현한 클래스만 사용 가능하고, 해당 클래스에서 clone() 메서드를 오버 라이딩해야 한다.
import java.util.*;
class Car implements Cloneable {
.....
@Override
public Object clone() { //clone
....
}
}
...
public static void main(String[] args) {
Car car01 = new Car("아반떼", "민지");
Car car02 = (Car)car01.clone();
car02.setOwners("지민");
}
protected void finalize()
- 해당 객체를 더는 아무도 참조하지 않아 가비지 컬렉터가 객체의 리소스를 정리하기 위해 호출한다.
Class<T> getClass()
- 해당 객체의 클래스 타입을 반환한다.
boolean equals()
- 인스턴스와 매개변수로 전달받는 참조 변수를 비교하여 그 결과를 반환한다. 두 변수의 값을 비교하기 때문에 주로 String type 값 비교에 많이 사용된다.
- str.equals(str2);
int hashCode()
- 해당 객체의 해시 코드값을 반환한다.
- hashCode는 HashTable과 같은 자료구조를 사용할 때 데이터가 저장되는 위치를 결정하기 위해 사용된다.
- 실행 중에 객체의 유일한 integer값을 반환한다. Object 클래스에서는 heap에 저장된 객체의 메모리 주소를 반환한다.
- equals()와 hashCode()의 관계
hashCode 메서드의 주석을 읽어보면 아래의 내용이 적혀있다.
1. 변경되지 않은 한 객체의 hashCode() 메서드를 호출한 결과는 항상 똑같은 integer 값이어야 한다. 객체가 변경됐더라도 equals 메서드가 참고하는 정보가 변경되지 않았다면 hashCode 값은 달라지지 않는다.
2. equals 메소드가 같다고 판별한 두 객체의 hashCode 호출 결과는 똑같은 integer 값이어야 한다.
3. 그러나 Object 클래스의 equals() 메서드가 다르다고 판별한 두 객체의 hashCode 값이 반드시 달라야 하는 것은 아니다.
내용을 토대로 hashCode 메소드가 equals와 밀접한 관련이 있음을 알 수 있다.
동일한 객체는 동일한 메모리 주소를 갖는다는 것을 의미하므로 equals() 메서드를 사용했을 때 true값을 반환하는 객체를 의미한다. 마찬가지로 hashCode() 메서드는 Object 클래스 객체에서 heap에 저장된 객체의 메모리 주소를 반환한다.
두 메서드의 관계를 정리하면 다음과 같다.
- 동일한 객체는 동일한 메모리 주소를 갖는다는 것을 의미하므로, 동일한 객체는 동일한 해시 코드를 가져야 한다. 그렇기 때문에 만약 equals() 메소드를 오버라이드 한다면, hashCode() 메서드도 오버라이드 되어야 한다.
- Java 프로그램을 실행하는 동안 equals에 사용된 정보가 수정되지 않았다면, hashCode는 항상 동일한 정수 값을 반환해야 한다. (Java의 프로그램을 실행할 때마다 달라지는 것은 상관이 없다.)
- 두 객체가 equals()에 의해 동일하다면, 두 객체의 hashCode() 값도 일치해야 한다
- 두 객체가 equals()에 의해 동일하지 않다면, 두 객체의 hashCode() 값은 일치하지 않아도 된다.
즉, obj1.equals(obj2) == True 이면 hashCode(obj1) == hashCode(obj2) 이여야하지만
hashCode(obj1) == hashCode(obj2)라고 obj1.equals(obj2) == True일 필요는 없다.
void notify()
- 해당 객체의 대기(wait)하고 있는 하나의 스레드를 다시 실행할 때 호출함.
void notifyAll()
- 해당 객체의 대기(wait)하고 있는 모든 스레드를 다시 실행할 때 호출함.
void wait()
- 해당 객체의 다른 스레드가 notify()나 notifyAll() 메서드를 실행할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.
void wait(long timeout)
- 해당 객체의 다른 스레드가 notify()나 notifyAll() 메서드를 실행하거나 전달받은 시간이 지날 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.
void wait(long timeout, int nanos)
- 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지나거나 다른 스레드가 현재 스레드를 인터럽트(interrupt) 할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.
- notify()와 wait()의 관계
위의 5가지 메서드가 공통으로 갖는 전제 조건이 보인다. 그것은 호출 스레드가 반드시 대상 객체의 고유 락을 갖고 있어야 한다는 것이다. 다시 말해, 이 메서드들은 synchronized 블록 내에서 실행되어야 한다. 고유 락을 획득하지 않은 상태에서 위 메서드들 중 하나를 호출하면 IllegalMonitorStateException가 발생한다.
notify() 메서드는 어느 스레드를 깨울지 선택할 수 없기 때문에 제어가 어렵다. 그래서 보통은 notifyAll()을 사용한다.
notifyAll()이 모든 스레드를 깨우긴 하지만 이 메서드를 호출한다고 해서 잠들어 있던 모든 스레드가 동시에 동작하는 것은 아니다. wait()으로 잠든 코드가 synchronized 블록 안에 있다는 것을 떠올려보자!
notifyAll()로 깨어난 스레드들은 다시 락을 획득하기 위해 경쟁해야 한다. 락을 획득한 스레드만이 wait() 함수를 리턴 시키고, 그다음 로직을 수행할 수 있다.
<참고>
-clone()
http://tcpschool.com/java/java_api_object
- hashCode()와 equals()
https://mangkyu.tistory.com/101
https://johngrib.github.io/wiki/Object-hashCode/
- notify()와 notifyAll()
http://happinessoncode.com/2017/10/05/java-object-wait-and-notify/
'JAVA' 카테고리의 다른 글
proxy 패턴 (0) | 2021.09.07 |
---|---|
디자인 패턴 (0) | 2021.08.06 |
Constant Pool (0) | 2021.08.05 |
StringBuffer / StringBuilder의 차이점 (0) | 2021.08.05 |
자바 환경설정 - JDK 버전 바꾸기 (0) | 2021.08.04 |