RTTI(Run-Time Type Information)
- 자바 프로그램의 실행(런타임)중에 타입 정보를 알아낼 수 있으며 사용도 가능하다
- 런타임 시 객체와 클래스의 정보를 알아내는 방법
첫번째는 전통적 RTTI로 컴파일 시점에 사용 가능한 모든 타입을 클래스에 내포
두번째는 리플렉션 매커니즘으로 런타임 시에 클래스의 정보만을 알고 사용할 수 있는 것
- OOP의 다형성은 전통적 RTTI로 자바 컴파일 시 상속구조를 파악하여 동작하는 원리
c의 프로그램 실행 과정
a.c a.o
a가 b를 참조 + link -> a.exe -> RAM으로 올리고, RAM에 올린 주소로 재배치한 뒤 파일 실행
b.c b.o
java의 프로그램 실행 과정
Java는 linking이 없고, jar를 이용해서 jar파일을 생성. a,b를 묶어 jar라는 파일로 합함
a.java -> a.class
+ a.jar -> JVM
b.java -> b.class
a를 실행하는 중에 b를 참조하게 되면 그 시점에 b를 로딩한 뒤 주소를 찾아온다
annotation 정의 및 사용
annotation 정의
@Target ({ElementType.TYPE, ElementType.METHOD}) // target과 retention 지정
@Retention (RetenthonPolicy.RUNTIME)
public @interface MyAnnotation{ // MyAnnotation이란 이름의 annotation 생성
int num();
String name();
String id();
String date() default "unsigned"; // 기본값을 지정할 수 있다
}
annotation 사용
@MyAnnotation(num=1,name='MainActivity",id="1")
public class MainActivity extends Activity{
@Override
@MyAnnotation(num=1,name="onCreate",id="2")
public void onCreate(Bundle savedInstanceState){
...
}
}
Java Reflect
동적으로 이름(String)을 이용하여 Java class를 다루는 방법
class를 메모리에 불러와서 class의 객체 생성
class의 method나 field를 이름과 signature를 이용하여 획득한 다음, 함수 호출 또는 값의 설정 및 획득
signature : 동일 이름(오버로딩) 등을 구분하기 위한 성질
Class class
Java의 class파일을 나타내는 class로 Class.forName()(ex: Class.Java.lang. 등 풀네임)과 같은 함수를 이용하여 Class 회득
Class의 newInstance()함수를 이용해 객체 생성
생성자를 이용하여 생성하고자 할 때, getConstructor()를 이용해 생성자를 얻어온 다음 생성자의 newInstance()를 이용해 객체 생성
Class가 메모리에 로딩되어 있지 않으면 ClassLoader를 이용해 메모리에 Class를 로딩해야 한다
Method class
class에 정의된 함수를 나타내는 class로서 Class 객체의 getMethod()를 호출하여 획득
getDeclaredMethod()로 protected나 private method도 얻어올 수 있음
invoke()로 함수 호출
Field
class에 정의 된 field를 나타내는 class로서 Class객체의 getField()를 호출하여 획득
get(),set() 함수를 이용하여 값을 설정하거나 얻어올 수 있음
Class 획득
Class clazz = Class.forName("org.tacademybasic.MyClass");
Class clazz = ClassLoader.loadClass("org.....MyClass");
Class clazz = MyClass.class; or Class clazz = MyClassObject.getClass();
객체의 생성
Object obj = clazz.newInstance();
Constructor c = clazz.getConstructor(String.class, Integer.class);
Object obj = c.newInstance("test",1);
ClassLoader
Class를 메모리에 로딩하기 위해 사용하는 class로 class가 설치된 패키지의 위치로부터 클래스를 읽어온다
ClassLoader.getSystemClassLoader()로 안드로이드 시스템의 클래스로더를 획득
이미 로딩된 클래스의 경우 getClassLoader()로 클래스로더를 얻어올 수 있다
PathClassLoader myClassLoader =
new dalvik.system.PathClassLoader(apkName, ClassLoader.getSystemClassLoader());
Class clazz = myClassLoader.loadClass(className);
Class clazz = Class.forName(className, true, myClassLoader);
Annotation
Class의 getAnnotation()으로 클래스에 정의된 어노테이션을 얻어올 수 있다
Method의 획득
Method method = clazz.getMethod("myMethod",String.class,interger.class);
Mythod method = clazz.getDeclaredMethod("myPrivateMethod",String.class,intsger.class);
Method[] methods[] = clazz.getMethods();
Method의 호출
method.invoke(myClassObject, "param1", 10); // instance method의 호출
method.invoke(null, "param1", 10); // static method의 호출
private method 호출
method.setAccessivle(true);
method.invoke(myClassObject, "param1", 10);
Method의 정보
getName() : 메소드 이름
getModifiers() : public, private, final, static 등의 정보
getParameterTypes() : paramter의 class[]
getReturnType() : return값의 class
Annotation 정보
getAnnotation()
getParameterAnnotation()
Field의 획득
Field field = clazz.getField("myField");
Field field = clazz.getDeclaredField("myPrivateField");
Field[] fields[] = clazz.getFields()l
Field값 획득 및 설정
Object value = field.get(myClassObject), field.set(myClassObject, valueObject);
Object value = field.get(null);, field.get(null, valueObject); // static field의 경우
그 외 값 획득 및 설정 함수
getBoolean(), getChar(), .....;
setBoolean(), setDouble(), ....;
Field의 정보
getName() : 필드 이름
getModifiers() : public, static 등의 정보
getType() : field의 class
getGenericType() : field의 Class<T>, GenericArraType, 등
Annotation 정보
메소드와 동일
Proxy class
interface를 implements한 클래스나 객체를 동적으로 생성해 주기 위한 class
reflect를 이용할 때 reflect로 생성한 object에 등록할 interface를 implements한 객체를 동적으로 생성
static Object newProxyInstance(ClassLoader loader, Class[] Interfaces, InvocationHandler hander)
InvocationHandler
newProxyInstance로 생성한 Object의 interface함수가 호출되면 InvocationHandler의 invoke가 호출된다
Object invoke(Object proxy, Method method, Object[] args)
Inboke함수에서는 method의 이름을 얻어와서 해당 method에 대한 처리 후 결과를 return한다
Class annotation check
Class clazz = AnnotationTest.class;
if(clazz.isAnnotationPresent(CheckAnnotation.class)){
CheckAnnotation ann = (CheckAnnotation) clazz.getAnnotation(CheckAnnotation.class);
int num = ann.num();
}
Method annotation check
Class clazz = AnnotationTest.class;
for(Method m : clazz.getMethods()){
if(m.isAnnotationPresent(CheckAnnotation.class)){
...
}
}
댓글