검색결과 리스트
리플렉션에 해당되는 글 3건
- 2011.04.07 리플렉션으로 Getter 와 Setter 검사하기
- 2011.04.07 (2) 리플렉션(Reflection) 사용하기
- 2011.04.07 (1) 리플렉션(Reflection) (3)
글
리플렉션으로 Getter 와 Setter 검사하기
클래스에 getter와 setter 메서드만을 검사할 수는 없으며, 모든 메서드들을 스캔하여 getter인지 setter인지를 확인해야 한다.
몇몇 setter는 값을 반환하지 않을 수도 있고 또 어떤 것은 집합값을 반환하거나 어떤 것들은 메서드 chaining을 위해
값을 반환할 수 있기 때문에 setter의 반환타입에 대한 가정을 해서는 안된다.
다음은 getter와 setter를 찾아 출력하는 예이다.
package com.tistory.hiddenviewer.reflection.executor; import java.lang.reflect.Method; import com.tistory.hiddenviewer.reflection.Board; public class GetterSetterPrinter { public static void main(String[] args) { printGettersSetters(Board.class); } public static void printGettersSetters(Class aClass){ Method[] methods = aClass.getMethods(); for(Method method : methods){ if(isGetter(method)) { System.out.println("getter: " + method); } if(isSetter(method)) { System.out.println("setter: " + method); } } // for } public static boolean isGetter(Method method){ // get 으로 시작하지 않으면 반환 if(!method.getName().startsWith("get")) { return false; } // 파라미터가 있으면 반환 if(method.getParameterTypes().length != 0) { return false; } // 반환값이 없으면 반환 if(void.class.equals(method.getReturnType())) { return false; } return true; }
public static boolean isSetter(Method method){ // set 으로 시작하지 않으면 반환 if(!method.getName().startsWith("set")) { return false; } // 파라미터가 개수가 1이 아니면 반환 if(method.getParameterTypes().length != 1) { return false; } return true; } }
출력결과
'언어로그 > Java' 카테고리의 다른 글
| Inner Class(내부 클래스) (0) | 2011.04.12 |
|---|---|
| 컬렉션(Collection) (0) | 2011.04.11 |
| 리플렉션으로 Getter 와 Setter 검사하기 (0) | 2011.04.07 |
| (2) 리플렉션(Reflection) 사용하기 (0) | 2011.04.07 |
| (1) 리플렉션(Reflection) (3) | 2011.04.07 |
| 예외처리 (Exception Handling) (0) | 2011.03.24 |
설정
트랙백
댓글
글
(2) 리플렉션(Reflection) 사용하기
방법에 대해 알아보자.
아래와 같이 3가지 단계를 거치게 되며 가장 먼저 클래스의 생성자 객체 java.lang.reflect.Consturctor 를 얻어야 한다.
다음과 같이 Class 객체로부터 Constructor 클래스를 얻는다.
// 생성자 목록 얻기 Class aClass = ... // 이전에 얻은 클래스 객체 Constructor[] constructors = aClass.getConstructors();
Constructor[] 배열은 클래스에 선언된 모든 public 생성자의 Constructor 인스턴스를 가집니다. 특정한 파라미터를 갖는
특정한 생성자는 다음과 같이 얻을 수 있다.
// 특정 파라미터를 갖는 생성자 얻기
Class aClass = ... // 이전에 얻은 클래스 객체
Constructor constructor =
aClass.getConstructor(new Class[]{String.class});
위 예는 하나의 String 타입 파라미터를 갖는 생성자를 반환하는데, 일치하는 파라미터를 갖는 생성자가 없으면
NoSuchMethodException 예외가 발생한다.
다음과 같이 생성자에 포함된 파라미터 타입 목록을 얻을 수 있다.
// 생성자의 파라미터 타입목록 얻기 Class aClass = ... // 이전에 얻은 클래스 객체 Class[] parameterTypes = constructor.getParameterTypes();
다음과 같이 생성자 객체로부터 객체를 생성한다.
// 하나의 String 파라미터를 갖는 생성자를 얻는다.
Constructor constructor = MyObject.class.getConstructor(String.class);
// 생성
MyObject myObject = (MyObject)constructor.newInstance("constructor-arg1");
Constructor.newInstance() 메서드는 선택적인 개수의 파라미터를 취한다. 하지만 반드시 해당 생성자에 맞는 개수와 타입의
// 클래스에 선언된 public 속성의 Field 객체얻기 Class aClass = ... // 이전에 얻은 클래스 객체 Field[] fields = aClass.getFields();
접근하려는 필드의 이름을 안다면, 다음과 같이 접근할 수 있다.
// Field에 접근하기
Class aClass = MyObject.class
Field field = aClass.getField("someField");
public class MyObject{
public String someField = null;
}
getField() 메서드의 파라미터에 해당하는 이름의 필드가 클래스에 존재하지 않으면 NoSuchFieldException 예외가 발생한다.
// Field 이름 얻기 Field field = ... // Field 객체를 얻는다. String fieldName = field.getName();
// Field 타입 얻기
Field field = aClass.getField("someField");
Object fieldType = field.getType();
Field 에 대한 참조를 얻게되면, Field.get(), Field.set() 메소드를 사용하여 값을 얻거나 설정할수 있다.
// Field 값 설정하고 조회하기
Class aClass = MyObject.class
Field field = aClass.getField("someField");
MyObject objectInstance = new MyObject();
Object value = field.get(objectInstance);
field.set(objetInstance, value);
field.get(), set() 메서드에는 해당 필드를 소유하는 객체가 인자로 전달되야 하며 만일 static 필드라면 null을 전달한다.
수 있지만, 단위테스트와 하이버네이트와 같은 프레임워크에서 유용하게 사용되기도 한다.
private 필드에 접근하기 위해서는 Class.getDeclaredField(String name)와 Class.getDeclaredFields() 메서드를 사용한다. (Class.getField(String name) 와 Class.getFields() 메서드는 public 필드만을 반환한다.)
다음은 private field에 접근하는 예이다.
Board board = new Board();
board.setContents("test contents...");
Field field = cls.getDeclaredField("contents");
field.setAccessible(true);
String contents = (String) field.get(board);
System.out.println("Private Contents Field: " + contents);
Field 객체의 setAccessible(true)를 호출하지 않고, private 필드값을 조회하려고 하면 IllegalAccessException 예외가 발생한다.
// Method 객체목록 얻기 Class aClass = ... // 이전에 얻은 클래스 객체 Method[] methods = aClass.getMethods();
해당 메서드의 인스턴스를 얻을 수 있다. 다음은 String 파라미터 하나를 갖는 doSomething 메소드의 Method 객체를 얻는다.
// 파라미터를 갖는 메소드의 Method 객체 얻기
Class aClass = ... // 이전에 얻은 클래스 객체
Method method = aClass.getMethod("doSomething", new Class[]{String.class});
배열 대신 null을 전달한다.
// 파라미터가 없는 메서드의 Method 객체 얻기
Class aClass = ... // 이전에 얻은 클래스 객체
Method method = aClass.getMethod("doSomething", null);
// 메서드의 파라미터 타입목록 얻기 Method method = ... // Class[] parameterTypes = method.getParameterTypes();
메서드의 반환타입은 다음과 같이 접근한다.
// 메서드의 반환값 타입 얻기 Method method = ... // Class returnType = method.getReturnType();
// 메서드 호출
Method method = MyObject.class.getMethod("doSomething", String.class);
Object returnValue = method.invoke(null, "parameter-value1");
Method.invoke(Object target, Object...parameters) 메서드는 선택적인 개수의 파라미터를 취하지만, 메서드가 필요로 하는
정확한 개수의 파라미터를 전달해야 한다.
Private Field 에 접근하는 것과 유사하게 Class.getDeclaredField(String name)와 Class.getDeclaredFields() 메서드를 사용한다.
(Class.getField(String name) 와 Class.getFields() 메서드는 public 필드만을 반환한다.)
'언어로그 > Java' 카테고리의 다른 글
| 컬렉션(Collection) (0) | 2011.04.11 |
|---|---|
| 리플렉션으로 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 |
설정
트랙백
댓글
글
(1) 리플렉션(Reflection)
작성할 수 있다. 하지만 리플렉션을 사용하면 좀더 유연한 프로그램을 작성할 수 있다. 자바에서 리플렉션을
이해하기 위해서, 자바 클래스 파일은 바이트 코드로 컴파일 되며 실행시간에 이 바이트 코드가 해석되어
실행된다는 것을 아는 것이 첫 출발점이 된다. 이 바이트 코드에는 클래스에 대한 모든 정보를 포함하고 있다.
클래스 파일이 있는 위치와 이 클래스 파일의 이름을 알수 있다면 언제든지 바이트 코드를 뒤져서 클래스에 대한
정보를 얻어낼 수 있다. 이제부터 리플렉션을 통해 어떻게, 어떤 정보를 얻을 수 있는지 알아보자.
1. 리플렉션(Reflection)
클래스를 사용할 수 있는 기법을 의미한다. 마치 거울에 비친 모습과 유사하여 리플렉션이란 이름을 붙힌 것 같다.
2. 리플렉션을 사용하는 이유
위임 클래스를 리플렉션을 통해 동적/정적으로 생성하고 교체하는 방식으로 사용된다. 프레임워크에서 유연성이 있는 동작을
위해 자주 사용되는 방식이기도 하다.
3. 리플렉션을 통해 얻을 수 있는 정보
ClassName Class Modifiers (public, private, synchronized 등) Package Info Superclass Implemented Interfaces Constructors Methods Fields Annotations
3.1 Class Object
프리미티 타입과 배열 타입을 포함하여 자바의 모든 타입들은 연관된 Class 객체를 가지고 있으며, 컴파일 타임에
클래스의 이름을 알수 있다면, 다음과 같이 Class 객체를 얻을 수 있다.
Class myObjectClass = MyObject.class컴파일 타임에 이름을 알수 없다면, 런타임에 문자열로 된 이름으로 부터 클래스 객체를 아래와 같이 얻을 수 있다.
String className = ... // 클래스 풀네임 Class myObjectClass = Class.forName(className);이때 문자열로 된 클래스 이름은 패키지 경로까지 포함한 풀네임이여야 하며, 해당 패키지에 클래스가 존재하지 않으면
Class.forName 메소드는 ClassNotFoundException 예외를 던지게 된다.
3.1 Class Name
있고, getSimpleName() 을 사용하여 패키지가 포함되지 않은 클래스 이름을 얻을 수 있다.
// 클래스 풀네임 Class aClass = ... // 이전에 얻은 클래스 객체 String className = aClass.getName();
// 클래스 심플 네임 Class aClass = ... // 이전에 얻은 클래스 객체 String simpleClassName = aClass.getSimpleName();
3.2 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();
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 클래스에 대한 정의는 아래와 같다.
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 필드에 접근 / 메소드를 호출 하는 방법에
대해 알아보자.
'언어로그 > 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 |