자바 성능 튜닝 - 클래스 정보 By starseat 2024-05-08 09:45:52 java/spring Post Tags [자바 성능 튜닝 이야기](https://product.kyobobook.co.kr/detail/S000001032977) 책을 읽고 정리한 내용 입니다. --- 자바에는 `Class` 클래스와 `Method` 클래스로 클래스와 메서드의 정보를 확인할 수 있는 API 가 있다. # reflection 관련 클래스들 자바 API에는 reflection 이라는 패키지가 있다. 이 패키지에 있는 클래스들을 사용하면 JVM에 로딩되어 있는 클래스와 메서드 정보를 읽어올 수 있다. 간단하게 살펴보자. ## Class 클래스 클래스에 대한 정보를 얻을 때 사용하기 좋다. ClassLoader 클래스의 defineClass() 메서드를 이용해서 클래스 객체를 만들 수도 있지만 좋은 방법은 아니다. 그보다는 Object 클래스에 있는 getClass() 메서드를 이용하는 것이 일반적이다. | method | 설명 | | -- | -- | | String getName() | 클래스 이름 반환 | | Package getPackage() | 클래스의 패키지 정보 반환 | | Field[] getFields() | public 으로 선언된 변수 목록 반환 | | Field getField(String name) | public 으로 선언된 변수 중 name 과 동일한 변수 반환 | | Field[] getDeclaredFields() | 해당 클래스에서 정의된 변수 목록 반환 | | Field getDeclaredField(String name) | name 과 동일한 이름으로 정의된 변수 반환 | | Method[] getMethods() | public 으로 선언된 모든 메서드 목록 반환해당 클래스에서 사용 가능한 상속받은 메서드도 포함 | | Method getMethod(String name, Class... parameterTypes) | 지정된 이름과 매개 변수 타입을 갖는 메서드 반환 | | Method[] getDeclaredMethods() | 해당 클래스에서 선언된 모든 메서드 정보 반환 | | Method getDeclaredMethod(String name, Class... parameterTypes) | 지정된 메서드 이름과 매개변수 타입을 갖는 해당 클래스에서 선언된 메서드 반환 | | Constructor[] getConstructors() | 해당 클래스에 선언된 모든 public 생성자 정보 반환 | | Constructor[] getDeclaredConstructors() | 해당 클래스에서 선언된 모든 생성자 정보 반환 | | int getModifiers() | 해당 클래스의 접근자(modifier) 정보 반환java 접근자: public, protected, private, final, static, native, volatile, abstract, synchronized, strictfp, transient | | String toString() | 해당 클래스의 객체를 문자열로 반환 | 현재 클래스의 이름을 알고 싶으면 다음과 같이 사용하면 된다. ```java String currentClassName = this.getClass().getName(); // 패키지 정보 포함 String currentClassSimpleName = this.getClass().getSimpleName(); // 클래스 이름만 ``` ## Method 클래스 `Method` 클래스를 이용하여 메서드에 대한 정보를 얻을 수 있다. `Method` 클래스는 생성자가 없으므로 `Class` 클래스의 `getMethod(), getDeclaredMethod()` 등을 사용하여야 한다. | method | 설명 | | -- | -- | | Class> getDeclaringClass() | 해당 메서드가 선언된 클래스 정보 반환 | | Class> getReturnType() | 해당 메서드의 리턴 타입 반환 | | Class>[] getParameterTypes() | 해당 메서드를 사용하기 위한 매개변수의 타입 목록 반환 | | String getName() | 해당 메서드의 이름 반환 | | int getMethodifiers() | 해당 메서드의 접근자 정보 반환 | | Class>[] getExceptionTypes() | 해당 메서드에 정의되어 있는 예와 타입 목록 반환 | | Object invoke(Object obj, Object... args) | 해당 메서드 수행 | | String toCenericString() | 타입 매개변수를 포함한 해당 메서드의 정보 반환 | | String toString() | 해당 메서드의 정보 반환 | ## Field 클래스 `Field` 클래스는 클래스에 있는 변수들의 정보를 제공한다. `Method` 클래스와 마찬가지로 생성자가 존재하지 않아 `Class` 클래스의 `getField(), getDeclaredFields()` 등의 메서드를 사용해야 한다. | method | 설명 | | -- | -- | | int getModifiers() | 해당 변수의 접근자 정보 반환 | | String getName() | 해당 변수 이름 반환 | | String toString() | 해당 변수 정보 반환 | # reflection 관련 클래스 사용 예 - DemoClass ```java public class DemoClass { // field (변수) private String privateField; String field; protected String protectedField; public String publicField; // Constructor (생성자) public DemoClass() {} public DemoClass(String arg) {} // Method (메서드) public void publicMethod() throws java.io.IOException, Exception {} public String publicMethod(String s, int i) { return "s=" + s + ", i=" + i; } protected void protectedMethod() {} private void privateMethod() {} void method() {} public String publicRetMethod() { return null; } public InnerClass getInnerClass() { return new InnerClass(); } public class InnerClass {} } ``` - DemoTest - 위의 DemoClass 테스트 ```java import java.lang.reflect.*; public class DemoTest { public static void main(String[] args) { DemoClass dc = new DemoClass(); // 점검 대상 클래스 객체 생성 DemoTest dt = new DemoTest(); dt.getClassinfos(dc); } public void getClassInfos(Object cls) { Class demoClass = cls.getClass(); getClassInfo(demoClass); getFieldInfo(demoClass); getMethodInfo(demoClass); } public void getClassInfo(Class demoClass) { System.out.println("[getClassInfo]"); System.out.format("Class Name: %s\n", demoClass.getName()); System.out.format("Class Canonical Name: %s\n", demoClass.getCanoicalName()); System.out.format("Class Simple Name: %s\n", demoClass.getSimpleName()); System.out.format("Paclage Name: %s\n", demoClass.getPackage().getName()); System.out.format("toString: %s\n", demoClass.toString()); } public void getFieldInfo(Class demoClass) { System.out.println("----------\n[getFieldInfo]"); Field[] field1 = demoClass.getDeclaredFields(); Field[] field2 = demoClass.getFields(); System.out.format("Declared Fields size: %d, Fields size: %d", field1.length, field2.length); for (Field field : field1) { System.out.format("%s %s %s\n", field.getName(), Modifier.toString(field.getModifiers()), Modifier.toString(modifier), field.getType().getSimpleName() ); } } public void getMethodInfo(Class demoClass) { System.out.println("----------\n[getMethodInfo]"); Method[] method1 = demoClass.getDeclaredMethods(); Method[] method2 = demoClass.getMethods(); System.out.format("Declared Methods size: %d, Methods size: %d", method1.length, method2.length); for(Method met : method1) { String methodName = met.getName(); String modifierStr = Modifier.toString(met.getModifiers()); String returnType = met.getReturnType().getSimpleName(); // method parameter info Class[] params = met.getParameterTypes(); StringBuilder paramSb = new StringBuilder(); int paramLen = params.length; if(paramLen > 0) { paramSb.append(params[0].getSimpleName()).append(" arg"); for(int i=0; i 0) { exceptionSb.append("throws").append(exceptions[0].getSimpleName()); for(int i=0; i Previous Post 자바 성능 튜닝 - static Next Post 자바 성능 튜닝 - Thread, synchronized