Java의 리플렉션이란?
- 컴파일 시점에 결정
- 프로그램이 실행 돼도 변하지 않음
- 오버로딩 : 컴파일 다형성, 메서드 타입,개수,순서 를 다르게 하여 정의하는 것
- private, final, static이 붙은 메서드
- 런타임 시점에 결정
- 오버라이딩 : 런타임 다형성, 부모,상위 클래스의 메서드를 하위 클래스가 재정의하여 사용하는 것
- Java에서의 다형성, 상속이 가능한 이유
클래스의 수정 없이 유연하게 확장 가능한 코드를 작성할 수 있다.
앞서 설명했던 것을 토대로 생각해보면, Reflection은 Runtime에 Class Type을 모르는채로 객체를 생성하고 이용하기 때문에 동적 바인딩을 제공한다.
해당 정보들을 통해 (1) 객체 생성 (2) 메서드 호출 (3) 변수 값을 변경할 수 있다.
[1] Class / Interface
public static void main(String[] args) throws Exception {
// 1. class를 알고 있을 경우
Class car = Car.class;
// 2. class 이름만 알고 있을 경우
Class car = Class.forName("com.reflection.test.Car");
// class.getName() -> com.reflection.test.Car
// 3. Default 생성자를 이용한 객체 생성
Car realCar = car.newInstance();
// 4. class에 구현된 interface 확인
Class[] interfaces = car.getInterfaces();
}
[2] Constructor
public static void main(String[] args) throws Exception {
Class car = Class.forName("com.reflection.test.Car");
// 1. 인자가 없는 생성자 가져오기
Constructor constructor = car.getDeclaredConstructor();
// 2. String 인자를 가진 생성자 가져오기
Constructor constructor = car.getDeclaredConstructor(String.class);
// 3. 모든 생성자 가져오기
Constructor constructors[] = car.getDeclaredConstructors();
// 4. public 생성자만 가져오기
Constructor constructors[] = car.getConstructors();
// public com.reflection.test.Car()
// public com.reflection.test.Car(java.lang.String)
// 5. 생성자를 이용한 객체 생성
Car realCar = constructor.newInstance();
}
[3] Method
public static void main(String[] args) throws Exception {
Class car = Class.forName("com.reflection.test.Car");
// 1. 인자가 없는 method 가져오기
Method method = car.getDeclaredMethod("move");
// 2. String 인자를 가진 method 가져오기
Method method = car.getDeclaredMethod("move", String.class);
// 3. 모든 method 가져오기
Method methods[] = car.getDeclaredMethods();
// 4. 상속받은 method와 public method 가져오기
Method methods[] = car.getMethods();
// public void com.reflection.test.Car.move()
// public void com.reflection.test.Car.move(java.lang.String)
// 5. method 호출
Class realCar = car.newInstance();
method.invoke(realCar, /*인자*/);
// 6. 접근 제한자를 무시한 method 호출.
method.setAccessible(true);
method.invoke(realCar, /*인자*/);
}
[4] Field
public static void main(String[] args) throws Exception {
Class car = Class.forName("com.reflection.test.Car");
// 1. car 객체에서 name 에 해당하는 field 가져오기
Field field = car.getDeclaredField("name");
// 2. car + car super 객체를 포함하여 name에 해당하는 field 가져오기
Field field = car.getField("name");
// 3. car 객체에 선언된 모든 field 가져오기
Field[] fields = car.getDeclaredFields();
// private java.lang.String com.reflection.test.Car.name
// public java.lang.Integer com.reflection.test.Car.type
// 4. car + car super 객체의 모든 public field 가져오기
Field[] fields = car.getFields();
// public java.lang.Integer com.reflection.test.Car.age
}
[5] Field 값 변경
public static void main(String[] args) throws Exception {
Class class = Class.forName("com.reflection.test.Car");
Constructor constructor = class.getConstructor()
Car car = constructor.newInstance()
Field field = car.getField("name");
// 1. public field 일 경우
field.set(car, "아반떼");
// 2. private field 일 경우
field.setAccessible(true);
field.set(car, "아반떼");
}