a.getClass() vs A.class

Gongmeda·2023년 1월 8일
1
post-thumbnail

java.lang.Class 클래스는 Java에서 제공하는 reflection 기능들을 사용하기 위한 entry point입니다

해당 클래스 타입의 객체를 얻을 수 있는 방법은 크게 두 가지가 있습니다

  1. Object.getClass() 메소드 호출
  2. .class 문법 사용

공통점

두 방법 모두 java.lang.Class 타입의 객체를 반환합니다

특정 클래스와 인스턴스에 대해 두 방법을 사용해 Class 타입 객체를 얻은 후 비교하면 동일하다는 결과를 확인할 수 있습니다

@Test
void test() {
	String s = "I am Groot";

	Class fromObject = s.getClass();
    Class fromClass = String.class;

	assertThat(fromObject).isEqualTo(fromClass); // Pass
}

차이점

Runtime vs Static

상속 관계에 있는 두 클래스를 선언하고 다음과 같은 테스트 코드를 실행했습니다

public class Person {
	protected String name;
}

public class Gongmeda extends Person {

}
@Test
void testWithInheritance() {
	Person person = new Gongmeda();

	Class fromObject = person.getClass();
	Class fromClass = Person.class;

	assertThat(fromObject).isEqualTo(fromClass); // Fail
}

코드에서 변수 personGongmeda 클래스의 인스턴스를 가르키고 있지만 부모 클래스인 Person 으로 선언되었습니다

따라서 person.getClass() 메소드의 결과 또한 Person 클래스일 것 같지만 메소드는 Gongmeda 클래스를 반환합니다

왜냐하면 변수 person 은 runtime에 Gongmeda 클래스 타입의 인스턴스를 가르키고 있으며, Object.getClass() 메소드는 runtime 기준의 타입을 반환하는 메소드이기 때문입니다

반면, .class 는 항상 해당 클래스에 대해 동일한(static한) 타입을 반환합니다

원시 타입

Object.getClass()Object 의 하위 타입들이 사용할 수 있는 메소드입니다

따라서 int 와 같은 원시 타입에 대해 사용할 경우 컴파일 오류가 납니다

error: int cannot be dereferenced
        Class numClass = num.getClass();
                            ^

반면, .class 문법을 원시 타입에 사용할 경우, 성공적으로 Class 객체를 반환합니다

@Test
void testWithPrimitiveType() {
	int num = 10;
	Class numClass = int.class; // Compile Success
    assertThat(numClass.getName()).isEqualTo("int"); // Pass
}

인스턴스가 없는 경우

package java.lang;

import jdk.internal.HotSpotIntrinsicCandidate;

public class Object {
	// ...
    
    @HotSpotIntrinsicCandidate
    public final native Class<?> getClass();
    
    // ...
}

위에서 확인할 수 있듯이 Object.getClass()Object 클래스에 존재하는 메소드입니다

따라서 Object 타입의 인스턴스에서만 사용할 수 있기 때문에 인스턴스를 만들지 않고 클래스에서는 직접 호출할 수 없습니다

이러한 경우에는 .class 문법을 사용해서 클래스에서 직접 static하게 Class 객체를 얻어야 합니다

참고

profile
백엔드 깎는 장인

0개의 댓글