7. 클래스 정보, 어떻게 알아낼 수 있나?
자바 API 중 reflection 패키지에 있는 클래스들을 사용하면 JVM에 로딩되어 있는 클래스와 메서드 정보들을 읽어 올 수 있다.
Class 클래스
Class 클래스는 클래스에 대한 정보를 얻을 때 사용하기 좋고, 생성자는 따로 없다. ClassLoader 클래스의 defineClass() 메서드를 이용해서 클래스 객체를 만들 수도 있지만, 좋은 방법은 아니다. 그보다는 Object 클래스에 있는 getClass() 메서드를 이용하는 것이 일반적이다.
- String getName(): 클래스의 이름을 리턴한다.
- Package getPackage(): 클래스의 패키지 정보를 패키지 클래스 타입으로 리턴한다.
- Field[] getFields(): public으로 선언된 변수 목록을 Field 클래스 배열 타입으로 리턴한다.
- Field getField(String name): public으로 선언된 변수를 Field 클래스 타입으로 리턴한다.
- Field[] getDeclaredFields(): 해당 클래스에서 정의된 변수 목록을 Field 클래스 배열 타입으로 리턴한다.
- Field getDeclaredField(String name): 해당 클래스에서 정의된 변수 목록을 Field 클래스 배열 타입으로 리턴한다.
- Method[] getDeclaredField(String name): name과 동일한 이름으로 정의된 변수를 Field 클래스 타입으로 리턴한다.
- Method[] getMethods(): public으로 선언된 모든 메서드 목록을 Method 클래스 배열 타입으로 리턴한다. 해당 클래스에서 사용 가능한 상속받은 메서드도 포함된다.
- Method getMethod(String name, Class… parameterTypes): 지정된 이름과 매개변수 타입을 갖는 메서드를 Method 클래스 타입으로 리턴한다.
- Method[] getDeclaredMethods(): 해당 클래스에서 선언된 모든 메서드 정보를 리턴한다.
- Method getDeclaredMethod(String name, Class… parameterTypes): 지정된 이름과 매개변수 타입을 갖는 해당 클래스에서 선언된 메서드를 Method 클래스 타입으로 리턴한다.
- Constructor[] getConstructors(): 해당 클래스에 선언된 모든 public 생성자의 정보를 Constructor 배열 타입으로 리턴한다.
- Constructor[] getDeclaredConstructors(): 해당 클래스에서 선언된 모든 생성자의 정보를 Constructor 배열 타입으로 리턴한다.
- int getModifiers(): 해당 클래스의 접근자(modifier) 정보를 int 타입으로 리턴한다.
- String toString(): 해당 클래스 객체를 문자열로 리턴한다.
현재 클래스의 이름을 알고 싶으면 다음과 같이 사용하면 된다.
String currentClassName = this.getClass().getName();
여기서 getName() 메서드는 패키지 정보까지 리턴해 준다. 클래스 이름만 필요한 경우에는 getSimpleName() 메서드를 사용하면 된다.
Method 클래스
Method 클래스를 이용하여 메서드에 대한 정보를 얻을 수 있다. 하지만 Method 클래스에는 생성자가 없으므로 Class 클래스의 getMethods() 메서드를 사용하거나 getDeclaredMethods() 메서드를 써야 한다.
Field 클래스
Field 클래스는 클래스에 있는 변수들의 정보를 제공하기 위해서 사용한다. Method 클래스와 마찬가지로 생성자가 없으므로 Class 클래스의 getFields()나 getDeclaredFields() 메서드를 써야 한다.
reflection 클래스를 잘못 사용한 사례
public String checkClass(Object src) {
if (src.getClass().getName().equals("java.math.BigDecimal")) {
// 데이터 처리
}
...
}
이렇게 사용할 경우 응답 속도에 그리 많은 영향을 주지는 않지만, 많이 사용하면 필요 없는 시간을 낭비하게 된다. 기본으로 돌아가서 다음과 같이 사용하면 좋다.
public String checkClass(Object src) {
if (src instanceof java.math.BigDecimal) {
// 데이터 처리
}
...
}
대상 | 응답 시간(마이크로초) |
---|---|
instanceof 사용 | 0.167 |
Reflection 사용 | 1.022 |
instanceof를 사용했을 때와 .getClass().getName()을 사용했을 때를 비교하면 약 6배의 성능 차이가 발생한다. 어떻게 보면 시간으로 보았을 때 큰 차이는 발생하지 않지만, 작은 것부터 생각하면서 코딩하는 습관을 가지는 것이 좋다.