검색결과 리스트
클래스 객체에 해당되는 글 1건
- 2011.04.07 (1) 리플렉션(Reflection) (3)
글
(1) 리플렉션(Reflection)
언어로그/Java
2011. 4. 7. 16:47
자바에서 리플렉션은 유연성을 제공하기 위해 필수적인 기법이다. 물론 리플렉션이 없더라도 훌륭한 코드를
작성할 수 있다. 하지만 리플렉션을 사용하면 좀더 유연한 프로그램을 작성할 수 있다. 자바에서 리플렉션을
이해하기 위해서, 자바 클래스 파일은 바이트 코드로 컴파일 되며 실행시간에 이 바이트 코드가 해석되어
실행된다는 것을 아는 것이 첫 출발점이 된다. 이 바이트 코드에는 클래스에 대한 모든 정보를 포함하고 있다.
클래스 파일이 있는 위치와 이 클래스 파일의 이름을 알수 있다면 언제든지 바이트 코드를 뒤져서 클래스에 대한
정보를 얻어낼 수 있다. 이제부터 리플렉션을 통해 어떻게, 어떤 정보를 얻을 수 있는지 알아보자.
작성할 수 있다. 하지만 리플렉션을 사용하면 좀더 유연한 프로그램을 작성할 수 있다. 자바에서 리플렉션을
이해하기 위해서, 자바 클래스 파일은 바이트 코드로 컴파일 되며 실행시간에 이 바이트 코드가 해석되어
실행된다는 것을 아는 것이 첫 출발점이 된다. 이 바이트 코드에는 클래스에 대한 모든 정보를 포함하고 있다.
클래스 파일이 있는 위치와 이 클래스 파일의 이름을 알수 있다면 언제든지 바이트 코드를 뒤져서 클래스에 대한
정보를 얻어낼 수 있다. 이제부터 리플렉션을 통해 어떻게, 어떤 정보를 얻을 수 있는지 알아보자.
1. 리플렉션(Reflection)
리플렉션은 구체적인 클래스 타입을 알지 못해도, 컴파일된 바이트 코드를 통해 역으로 클래스에 정보를 알아내어
클래스를 사용할 수 있는 기법을 의미한다. 마치 거울에 비친 모습과 유사하여 리플렉션이란 이름을 붙힌 것 같다.
클래스를 사용할 수 있는 기법을 의미한다. 마치 거울에 비친 모습과 유사하여 리플렉션이란 이름을 붙힌 것 같다.
2. 리플렉션을 사용하는 이유
리플렉션은 조합(Composition)과 함께 사용되어 다형성을 구현하는 강력한 도구이다. 조합을 사용하여 교체할 수 있는
위임 클래스를 리플렉션을 통해 동적/정적으로 생성하고 교체하는 방식으로 사용된다. 프레임워크에서 유연성이 있는 동작을
위해 자주 사용되는 방식이기도 하다.
위임 클래스를 리플렉션을 통해 동적/정적으로 생성하고 교체하는 방식으로 사용된다. 프레임워크에서 유연성이 있는 동작을
위해 자주 사용되는 방식이기도 하다.
3. 리플렉션을 통해 얻을 수 있는 정보
리플렉션을 통해 얻을 수 있는 정보에 대해서 알아보자.
ClassName Class Modifiers (public, private, synchronized 등) Package Info Superclass Implemented Interfaces Constructors Methods Fields Annotations
3.1 Class Object
클래스 정보를 얻기 위해 가장 먼저 해야할 일은 정보를 담고 있는 java.lang.Class 객체를 획득하는 것이다.
프리미티 타입과 배열 타입을 포함하여 자바의 모든 타입들은 연관된 Class 객체를 가지고 있으며, 컴파일 타임에
클래스의 이름을 알수 있다면, 다음과 같이 Class 객체를 얻을 수 있다.
프리미티 타입과 배열 타입을 포함하여 자바의 모든 타입들은 연관된 Class 객체를 가지고 있으며, 컴파일 타임에
클래스의 이름을 알수 있다면, 다음과 같이 Class 객체를 얻을 수 있다.
Class myObjectClass = MyObject.class컴파일 타임에 이름을 알수 없다면, 런타임에 문자열로 된 이름으로 부터 클래스 객체를 아래와 같이 얻을 수 있다.
String className = ... // 클래스 풀네임 Class myObjectClass = Class.forName(className);이때 문자열로 된 클래스 이름은 패키지 경로까지 포함한 풀네임이여야 하며, 해당 패키지에 클래스가 존재하지 않으면
Class.forName 메소드는 ClassNotFoundException 예외를 던지게 된다.
3.1 Class Name
Class 객체로부터 2가지 버전의 클래스 이름을 얻을 수 있다. getName() 메소드를 사용하면 패키지까지 포함한 풀네임을 얻을 수
있고, getSimpleName() 을 사용하여 패키지가 포함되지 않은 클래스 이름을 얻을 수 있다.
있고, getSimpleName() 을 사용하여 패키지가 포함되지 않은 클래스 이름을 얻을 수 있다.
// 클래스 풀네임 Class aClass = ... // 이전에 얻은 클래스 객체 String className = aClass.getName();
// 클래스 심플 네임 Class aClass = ... // 이전에 얻은 클래스 객체 String simpleClassName = aClass.getSimpleName();
3.2 Modifier
Class 객체로부터 변경자에 접근할 수 있다. 클래스 변경자는 public, private, static 과 같은 키워드를 의미한다.
클래스에 대한 플래그 비트가 설정된 int 값을 얻을 수 있으며 java.lang.reflect.Modifier 클래스에 있는 메소드를
통해 해당 플래그가 켜져있는지 확인할 수 있다.
통해 해당 플래그가 켜져있는지 확인할 수 있다.
// 변경자 얻기 Class aClass = ... // 이전에 얻은 클래스 객체 int modifiers = aClass.getModifiers();
// 변경자 플래그 확인 메소드들 Modifier.isAbstract(int modifiers) Modifier.isFinal(int modifiers) Modifier.isInterface(int modifiers) Modifier.isNative(int modifiers) Modifier.isPrivate(int modifiers) Modifier.isProtected(int modifiers) Modifier.isPublic(int modifiers) Modifier.isStatic(int modifiers) Modifier.isStrict(int modifiers) Modifier.isSynchronized(int modifiers) Modifier.isTransient(int modifiers) Modifier.isVolatile(int modifiers)
3.3 Package Info
다음과 같이 Class 객체로부터 패키지에 대한 정보를 얻는다.
// 패키지 정보 얻기 Class aClass = ... // 이전에 얻은 클래스 객체 Package package = aClass.getPackage();
Package 객체로부터 패지지 이름과 같은 정보에 접근할 수 있다. 또한 패키지가 위치한 classpath에 있는jar 파일의
Manifest 파일에서도 이 패키지에 대한 특정한 정보를 얻을 수 있다.
(예를 들면 Manifest 파일에 지정된 패지키 버전 번호 같은...)
Manifest 파일에서도 이 패키지에 대한 특정한 정보를 얻을 수 있다.
(예를 들면 Manifest 파일에 지정된 패지키 버전 번호 같은...)
3.4 Superclass
아래와 같이 수퍼클래스의 class 객체를 얻을 수 있다.
// 수퍼 클래스의 class 객체 얻기 Class superclass = aClass.getSuperclass();
3.5 Implemented Interfaces
클래스 객체에 의해 구현된 인터페이스의 목록을 얻어보자.
// 구현한 인터페이스 목록 얻기 Class aClass = ... // 이전에 얻은 클래스 객체 Class[] interfaces = aClass.getInterfaces();
수퍼클래스가 구현한 인터페이스지만, 자식클래스가 특별히 해당 인터페이스를 구현한다고 명시하지 않으면,
해당 인터페이스는 목록에 포함되지 않는 것에 주의하자. 구현하는 완전한 인터페이스의 목록을 얻기 위해서는
자신의 수퍼클래스의 구현 인터페이스 목록을 재귀적으로 확인해야 한다.
해당 인터페이스는 목록에 포함되지 않는 것에 주의하자. 구현하는 완전한 인터페이스의 목록을 얻기 위해서는
자신의 수퍼클래스의 구현 인터페이스 목록을 재귀적으로 확인해야 한다.
3.6 Constructors
다음과 같이 클래스의 생성자 목록에 접근한다.
// 클래스 생성자 목록 얻기 Constructor[] constructors = aClass.getConstructors();
3.7 Methods
다음과 같이 클래스의 메소드들에 접근한다.
// 메소드 목록 얻기 Method[] methods = aClass.getMethods();
3.8 Fields
다음과 같이 클래스의 멤버 변수들에 접근한다.
// 필드 목록 얻기 Field[] fields = aClass.getFields();
3.9 Annotations
다음과 같이 클래스의 어노테이션에 접근한다.
// 어노테이션 목록 얻기 Annotation[] annotations = aClass.getAnnotations();
※ 리플렉션을 사용하여 Annotation을 처리하는 것은 아래 포스트를 참고!!
Java-어노테이션(Annotation)
Java-어노테이션 사용하기
4. 리플렉션 사용 예
게시물 정보를 갖는 Board 클래스에 대한 정보를 리플렉션을 사용하여 출력하는 예를 보자.
Board 클래스에 대한 정의는 아래와 같다.
Board 클래스에 대한 정의는 아래와 같다.
package com.tistory.hiddenviewer.reflection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
public class Board implements ActionListener{
public final static String boardName = "MyBoard";
public ArrayList boardList;
public int seq;
protected String title;
private String contents;
public Board() {
this(10);
}
public Board(int count) {
this.boardList = new ArrayList(count);
}
public int getSeq() {
return seq;
}
public void setSeq(int seq) {
this.seq = seq;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContents() {
return contents;
}
public void setContents(String contents) {
this.contents = contents;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
Board 클래스에 대한 정보를 리플렉션을 사용하여 출력하였다.
package com.tistory.hiddenviewer.reflection.executor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class BoardReflectionExecutor {
public static void main(String[] args) throws IOException, ClassNotFoundException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("생성할 클래스 이름을 입력하세요(패키지 포함): ");
String className = br.readLine();
Class cls = Class.forName(className);
// 클래스 이름얻기
String classFullName = cls.getName();
String classSimpleName = cls.getSimpleName();
System.out.println("class full name: " + classFullName);
System.out.println("class simple name: " + classSimpleName);
// 변경자 얻기
int modifiers = cls.getModifiers();
if (Modifier.isPublic(modifiers)) {
System.out.println("class is public class");
}
if (Modifier.isFinal(modifiers)) {
System.out.println("class is final class");
}
// 패키지 얻기
Package pkg = cls.getPackage();
System.out.println("package name: " + pkg.getName());
// 수퍼클래스 얻기
Class superCls = cls.getSuperclass();
System.out.println("super class name :" + superCls.getName());
// 구현 인터페이스 목록 얻기
Class[] interfaces = cls.getInterfaces();
for (Class cs : interfaces) {
System.out.println("this class implements " + cs.getName() + " interface");
}
// 생성자 목록 얻기
Constructor[] conturctors = cls.getConstructors();
for (Constructor constructor : conturctors) {
System.out.println("Constructor: " + constructor.getName());
}
// 메서드 목록 얻기
Method[] methods = cls.getMethods();
for (Method method : methods) {
System.out.println(method.getReturnType() + " " + method.getName() + "(...)");
}
// 프로퍼티 목록 얻기
Field[] fields = cls.getFields();
for (Field field : fields) {
System.out.println(field.getType() + " " + field.getName());
}
// 어노테이션 얻기
Annotation[] annotations = cls.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
}
}
출력결과
출력 결과를 보면 알겠지만 private, protected 변경자를 갖는 필드들은 출력되지 않고 public 필드들만 출력이 되었다.
다음 포스팅에서는 리플렉션을 사용하여 실세로 해당 타입의 객체를 생성 / private 필드에 접근 / 메소드를 호출 하는 방법에
대해 알아보자.
다음 포스팅에서는 리플렉션을 사용하여 실세로 해당 타입의 객체를 생성 / private 필드에 접근 / 메소드를 호출 하는 방법에
대해 알아보자.
'언어로그 > Java' 카테고리의 다른 글
| 리플렉션으로 Getter 와 Setter 검사하기 (0) | 2011.04.07 |
|---|---|
| (2) 리플렉션(Reflection) 사용하기 (0) | 2011.04.07 |
| (1) 리플렉션(Reflection) (3) | 2011.04.07 |
| 예외처리 (Exception Handling) (0) | 2011.03.24 |
| [Java] 어노테이션 사용하기 (1) | 2011.03.19 |
| [Java] 어노테이션(Annotation) (2) | 2011.03.15 |