// Object.class - java17
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
Object 클래스는, 클래스 계층 구조의 루트입니다. 모든 클래스는 Object.class를 Super 클래스로 가지고 있습니다. 배열을 포함한 모든 개체는 이 클래스의 메서드를 구현합니다.
Java에서 'Object' 클래스는 클래스 계층 구조의 최상위 클래스이자 모든 클래스의 부모 클래스이므로, 모든 클래스는 'Object' 클래스를 직간접적으로 상속받는다.
Object Class의 메서드
Java에서 모든 클래스가 'Object' 클래스를 직간접적으로 상속받으므로, 'Object' 클래스의 메서드 또한 상속받게 된다. 클래스 오브젝트에서 사용할 수 있는 메서드는 다음과 같다
Object Class가 가지고 있는 public 메서드
- getClass()
- 런타임 클래스 객체(Runtime class object)의 정보를 가져온다
- JVM의 클래스 로더가 힙 영역에 Class 객체를 생성하고, 이 객체의 인스턴스를 런타임 클래스 객체라고 말한다
- parameter : x
- return : 실행중인 객체의 클래스 정보를 가지고 있는 Class<?> 객체
- Runtime Class Object의 메서드
- getName() : Class의 이름을 반환
- getFileds() : 클래스의 필드를 반환
- getConstructors() : 클래스의 생성자를 반환
- getMethods() : 클래스의 메서드를 반환
getClass() 확인 코드
더보기
// 임의의 Class를 선언
public class ObjectClass {
public String a = "hello, world";
public Integer b = 28;
public ObjectClass(String a, Integer b) {
this.a = a;
this.b = b;
}
public void method() {
System.out.println("hello, world");
}
}
// ObejctClass를 생성하여, [getClass, getName, getFields, getConstructors, getMethods] 메서드의 결과값을 확인
public class ClassTest {
private static ObjectClass objectClass = new ObjectClass("hello, world", 28);
public static void main(String[] args) throws NoSuchFieldException {
// getClass 메서드
Class<? extends ObjectClass> objClass = objectClass.getClass();
System.out.println("getClass(): " + objClass);
// getName 메서드
String className = objectClass.getClass().getName();
System.out.println("\ngetName(): " + className);
// getFields 메서드
Field[] fields = objectClass.getClass().getFields();
System.out.println("\ngetFields(): " + fields);
for (Field field:fields) {
System.out.println("원소 출력: " + field);
}
// getConstructors 메서드
Constructor<?>[] constructors = objectClass.getClass().getConstructors();
System.out.println("\ngetConstructors(): " + constructors);
for (Constructor<?> constructor:constructors) {
System.out.println("원소 출력: " + constructor);
}
// getMethods 메서드
Method[] methods = objectClass.getClass().getMethods();
System.out.println("\ngetMethods(): " + methods);
for (Method method:methods) {
System.out.println("원소 출력: " + method);
}
}
}
- hashCode()
- 객체의 해시코드를 반환해줌
- 기본값은 객체의 주소값을 해시코드로 반환시켜주기 때문에, 객체의 주소가 아닌 다른 데이터의 주소를 반환하기 위해서는 오버라이딩하여 재정의 해야한다
- 오버라이딩하여 같은 '값'을 가지면, 다른 객체더라도 동일한 해시코드를 반환하게끔 사용할 수 있다
hashCode() 확인코드
더보기
// overriding 하지 않은 hashCode 메서드
System.out.println("\nobjectClass.hashCode(): " + objectClass.hashCode());
System.out.println("objectClass2.hashCode() = " + objectClass2.hashCode());
// overriding한 hashCode() 메서드: 필드값 주소를 해시값으로 반환한다
@Override
public int hashCode() {
return Objects.hash(a, b);
}
System.out.println("\nobjectClass.hashCode(): " + objectClass.hashCode());
System.out.println("objectClass2.hashCode() = " + objectClass2.hashCode());
- equals(Object o)
- 두 객체가 동일한지 비교할 때 사용됨
- 기본값은 객체의 주소값으로 동등 비교를 진행하기 때문에, 동등 비교 기준을 변경하기 위해서는 오버라이딩하여 재정의 해야한다
- 오버라이딩하여 같은 '값'을 가지면, 다른 객체더라도 동등하다고 반환하게끔 사용할 수 있다
equals(Object o) 확인코드
더보기
// overriding 하지 않은 equals 메서드 결과
private static ObjectClass objectClass = new ObjectClass("hello, world", 28);
ObjectClass objectClass2 = new ObjectClass("hello, world", 28);
System.out.println("\nobjClass & objClass2 equals(): " + objectClass.equals(objectClass2));
// overrinding한 equals 메서드 : 다른 객체더라도 같은 '값'을 가지면 true를 반환
@Override
public boolean equals(Object obj) {
if (obj instanceof ObjectClass) {
ObjectClass objectClass = (ObjectClass) obj;
return a.equals(objectClass.a) && b.equals(objectClass.b);
}
return super.equals(obj);
}
private static ObjectClass objectClass = new ObjectClass("hello, world", 28);
ObjectClass objectClass2 = new ObjectClass("hello, world", 28);
System.out.println("\nobjClass & objClass2 equals(): " + objectClass.equals(objectClass2));
- toString()
- 해당 인스턴스의 '클래스이름@인스턴스의 주소(16진수 해시코드)'를 반환한다(print(객체) 와 동일한 결과값)
- 기본적으로 객체를 출력(println)할 때, 변수에 toString()을 호출하지 않아도 자동으로 붙여서 호출한다
- 객체의 고유 정보를 출력하고 싶다면, toString을 재정의하여 반환값을 다르게 설정해주면 된다
toString() 확인코드
더보기
// toString 메서드
System.out.println("\ntoString(): " + objectClass.toString());
System.out.println("println: "+ objectClass);
- notify()
- 대기 상태인 Thread중, '임으로 하나'를 골라서 다시 RUNNABLE 상태로 변경시키는 역할을 한다
- 어떤 Thread를 깨울 지 선택할 수 없으므로 제어가 어렵다
- 메서드를 호출하는 Thread가 반드시 고유 락을 갖고 있어야 한다. 다시 말해, synchronized 블록 내에서 호출되어야 한다
- notifyAll()
- notify()와 마찬가지로 대기 상태인 Thread를 다시 RUNNABLE 상태로 변경시키는 역할을 한다
하지만 notify()와 다르게, '대기 상태인 모든 Thread'를 RUNNABLE 상태로 변경시킨다 - notifyAll()을 사용한다고 해서 대기상태인 모든 Thread가 '동시에' 동작하는 것은 아니고, 다시 제어권(락)을 획득하기 위해 경쟁한다. 이후 제어권을 획득한 Thread만이 wait()를 리턴시키고 다음 로직을 수행할 수 있다
- 메서드를 호출하는 Thread가 반드시 고유 락을 갖고 있어야 한다. 다시 말해, synchronized 블록 내에서 호출되어야 한다
- notify()와 마찬가지로 대기 상태인 Thread를 다시 RUNNABLE 상태로 변경시키는 역할을 한다
- wait()
- 자원을 소유한 Thread가, 자신의 제어권을 양보하고 대기상태로 들어가기 위해 사용된다
- 메서드를 호출하는 Thread가 반드시 고유 락을 갖고 있어야 한다. 다시 말해, synchronized 블록 내에서 호출되어야 한다
복습 Question
- 모든 클래스들이 공통적으로 상속하는 메서드는 어떤게 있을까?
- equals()와 hashcode()는 기본적으로 '주소값'으로 동작하게 된다. 이를 '값'으로 동작하게 하려면 어떻게 재정의 코드를 작성 해야할까?
- wait(), notifyAll()을 사용하여 다음의 요구사항을 충족시키는 블로킹 큐를 구현해보자
(참고 : http://happinessoncode.com/2017/10/05/java-object-wait-and-notify/)
- 생성 시점에 용량(capacity)이 결정된다.
- 큐가 비어있을 때 요소를 빼내려고 하면 빼낼 요소가 들어올 때까지 스레드가 블로킹된다.
- 용량이 꽉 찼을 때 요소를 추가하려고 하면 빈 공간이 생길 때까지 스레드가 블로킹된다.
Reference
- Object 클래스 wait, notify, notifyAll : https://gyoogle.dev/blog/computer-language/Java/Wait%20&%20notify%20&%20notifyAll.html
- Object 클래스의 getClass 메서드 : https://developer-talk.tistory.com/758
- 모든 클래스는 Object 클래스를 상속받는다: https://www.codelatte.io/courses/java_programming_basic/6SV594GBY4V2GY1X#head2
- Object 클래스의 wait와 notify의 사용법 : http://happinessoncode.com/2017/10/05/java-object-wait-and-notify/