목차
- Refleciton과 Class 클래스
- Class 객체 얻기
- 필드와 메소드
- Class 객체로부터 원하는 객체 얻기
- Method.invoke()
글 시작전에...
Class는 class의 하나로서 아래와 같이 선언되어있다
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
....
...
...
...
}
class: 우리가 객체와클래스 배울 때 배우던 그거.
Class: 자바의 여러 class 중 하나
헷갈리니까 Class는 그대로 Class로, class는 한글로 클래스 라고 하겠다
Reflection과 Class 클래스란
먼저 Reflection이란 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법을 말한다.
투영,반사 라는 사전적인 의미를 지니고 있다.
이 말만으로는 Reflection이 뭔지 이해하기 쉽지않다.
Class를 먼저 알아보자.
자바는 클래스와 인터페이스 메타 데이터를 java.lang 패키지에 소속된 Class 클래스로 관리한다.
여기서 메타 데이터란
- 클래스의 이름
- 생성자
- 필드
- 메소드
를 말한다. 즉, Class 클래스는 어떤 클래스의 구조 자체를 하나의 클래스로 표현해놓은 클래스입니다.
Class 클래스 내부의 메서드를 보시면 이해가 편하실 겁니다.
Class 클래스에 정의된 메서드들의 목록입니다.
반환형인 Field, Method, Package, Constructor 등은
모두 reflect 패키지에서 제공해주는 클래스들입니다.
특정 클래스의 정보들인 Field, Method, 클래스 이름 등에 대한 정보들을
관리하는 클래스가 Reflection 클래스이고
java.lang.reflect 패키지에서 관리합니다.
다음과 같이 Square 클래스가 있습니다.
package study;
public class Square {
private int bottomLine;
private int height;
private String squareName;
public int getArea() {
return bottomLine*height;
}
public static int staticGetArea(int bottomLine, int height){
return bottomLine*height;
}
public int getBottomLine() {
return bottomLine;
}
public void setBottomLine(int bottomLine) {
this.bottomLine = bottomLine;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getSquareName() {
return squareName;
}
public void setSquareName(String squareName) {
this.squareName = squareName;
}
}
자바는 이 Square 클래스에 대한 정보를 Class 클래스로 관리합니다.
즉, Class 클래스를 통해 Square 클래스에 대한 정보를 얻고
또 특정 메소드를 대신 실행할 수도 있습니다.
Class 객체 얻기
Class 클래스의 객체를 얻는 방법은 2가지가 있습니다. getClass()와 forName()
설명은 따로 필요없고 사용법만 봅시다. 2메소드 전부 return Type이 Class 입니다.
import study.Square ;
public class Main {
public static void main(String[] args) throws Exception {
Class clazz= Square .class;
Class clazz2= Class.forName("study.Square"); //패키지명까지 풀 네임으로 써야합니다.
//forName 파라미터 이름이 틀리면 에러나니까 그냥 main메소드에서 에러던짐
}
}
clazz와 clazz2 모두 Square클래스의 정보를 갖고있는 Class 타입의 객체가 되겠습니다.
실습에서는 clazz객체로만 하겠습니다.
필드와 메소드
Class 클래스에서 필드와 메소드를 얻을 때
getDelcared와 get이 있는데
getDeclaredFiled()는 해당 클래스에서 선언된 필드만 얻는다. (private, public 다 되긴함)
getField()는 상속된 필드도 얻을 수 있다 (단, public만 됨)
-메소드도 마찬가지-
(private 일 때 꼭 접근해야 한다면 setAccessible(true)를 이용하면 private이어도 접근가능함)
clazz 객체로부터 Square클래스의 필드와 메소드에 대한 정보를 얻어보겠습니다.
Main.java
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.Signature;
import study.Square;
public class Main {
public static void main(String[] args) throws Exception {
Class clazz= Square.class;
Class clazz2= Class.forName("study.square"); //패키지명까지 풀 네임으로 써야합니다.
//forName 파라미터 이름이 틀리면 에러나니까 그냥 main메소드에서 에러던짐
System.out.println("------------모든 필드에 대한 정보 ---------------");
Field[] fileds= clazz.getDeclaredFields();
for(Field field: fileds) {
System.out.println("필드이름 : "+field.getName()+ " 필드 타입:"+field.getType());
}
System.out.println("-----------특정 필드에 대한 정보 ---------------");
Field field= clazz.getDeclaredField("bottomLine");
System.out.println("필드이름 : "+field.getName()+ " 필드 타입:"+field.getType());
System.out.println();
System.out.println();
System.out.println("-----------모든 메소드에 대한 정보 ---------------");
Method[] methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println("메소드이름 : "+method.getName()
+" 메소드 파라미터 수:"+method.getParameterCount()
+" 메소드 리턴 타입"+ method.getReturnType());
}
System.out.println("-----------특정 메소드에 대한 정보 ---------------");
Method methodGetArea= clazz.getDeclaredMethod("getArea");
Method methodStaticGetArea=clazz.getDeclaredMethod("staticGetArea",int.class,int.class);
// 이런식으로 메소드 얻으면 된다. 파라미터 쓰는 방법만 유의깊게 보자.
}
}
Class 객체로부터 원하는 객체 얻기
Class 객체 clazz로부터 Square객체를 생성해보겠습니다.
Square square= (Square)clazz.newInstance();
Method.invoke()
특정 메소드 얻는 방법은 다음과 같습니다.
Method method = clazz.getMethod("testMethod"); // 파라미터 없는 메서드
Method method2 = clazz.getMethod("testMethod", null); // null을 줘도 됨
Method method3 = clazz.getMethod("testMethod", String.class); // 파라미터 1개
Method method4 = clazz.getMethod("testMethod", new Class[]{String.class, Integer.class}); // 2개 이상
Square에는 객체의 높이와 밑변을 곱해 넓이를 구하는 getArea()메소드가 있습니다.
getArea는 해당 객체의 넓이를 구하는 거기 때문에 객체를 얻어야만 쓸 수 있습니다.
그래서 매개변수로 sqrue 객체가 들어갑니다.
또 static 메소드는 객체가 없기 때문에 null, 나머지는 파라미터 원하는 것 만큼 넣어주면 됩니다.
System.out.println("-----------특정 메소드 얻어서 사용하기-----------------------");
Method methodGetArea= clazz.getDeclaredMethod("getArea");
Method methodStaticGetArea=clazz.getDeclaredMethod("staticGetArea",int.class,int.class);
// 이런식으로 메소드 얻으면 된다. 파라미터 쓰는 방법만 유의깊게 보자.
Square square= (Square)clazz.newInstance();
square.setBottomLine(5); square.setHeight(20);
System.out.println("square 객체의 넓이 : "+methodGetArea.invoke(square));
System.out.println("static메소드 넓이 구하기 : "+methodStaticGetArea.invoke(null,10,20));
전체 Main.java
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.Signature;
import java.util.Scanner;
import study.Square;
public class Main {
public static void main(String[] args) throws Exception {
Class clazz= Square.class;
Class clazz2= Class.forName("study.square"); //패키지명까지 풀 네임으로 써야합니다.
//forName 파라미터 이름이 틀리면 에러나니까 그냥 main메소드에서 에러던짐
System.out.println("------------모든 필드에 대한 정보 ---------------");
Field[] fileds= clazz.getDeclaredFields();
for(Field field: fileds) {
System.out.println("필드이름 : "+field.getName()+ " 필드 타입:"+field.getType());
}
System.out.println("-----------특정 필드에 대한 정보 ---------------");
Field field= clazz.getDeclaredField("bottomLine");
System.out.println("필드이름 : "+field.getName()+ " 필드 타입:"+field.getType());
System.out.println();
System.out.println();
System.out.println("-----------모든 메소드에 대한 정보 ---------------");
Method[] methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println("메소드이름 : "+method.getName()
+" 메소드 파라미터 수:"+method.getParameterCount()
+" 메소드 리턴 타입"+ method.getReturnType());
}
System.out.println("-----------특정 메소드 얻어서 사용하기-----------------------");
Method methodGetArea= clazz.getDeclaredMethod("getArea");
Method methodStaticGetArea=clazz.getDeclaredMethod("staticGetArea",int.class,int.class);
// 이런식으로 메소드 얻으면 된다. 파라미터 쓰는 방법만 유의깊게 보자.
Square square= (Square) clazz.newInstance();
square.setBottomLine(5); square.setHeight(20);
System.out.println("square 객체의 넓이 : "+methodGetArea.invoke(square));
System.out.println("static메소드 넓이 구하기 : "+methodStaticGetArea.invoke(null,10,20));
}
}