(Java)Private Method 호출하기

DevSeoRex·2022년 5월 31일
1

Java

목록 보기
10/15

Java를 처음 배우고 자바의 정석,이것이 자바다 등을 통해서 자바를 공부한지 3달차가 되어간다. 접근제한자를 배우면서 private 접근제한자가 붙어있으면 무조건 사용이 안된다고 머리속에 넣어놓고 있었다. 또, private 접근제한자가 붙어 있는 경우에는 변수의 경우 getter & setter Method를 사용하여 어느정도는 다룰 수 있었지만 private Method를 호출해서 사용한다는 생각은 해본 적이 없는 것 같다.

이러던 와중에 자바의 정석 저자이신 남궁성 선생님의 "Spring의 정석" 을 수강하다가 재밌는 것을 발견했다.

Java에서 클래스 정보(접근제한자와 상관없이)를 얻어내고 그 안에 있는 내용들을 사용할 수 있게 해주는 강!력!한 API인 Reflection API 이다.

1. Paramemter가 없는 메서드 호출

public class PrivateClass {
	private void method1() {
		System.out.println("private Method1");
	}
	private void method2(int a,int b) {
		int c = a+b;
		System.out.println("a + b = " +c );
	}
}

호출의 대상이 될 PrivateClass를 작성해 주었다.
Method1은 매개변수가 없는 메서드로 작성하였고, Method2는 매개변수를 입력받아, 연산을 하고 출력해주는 형식으로 작성하였다.

import java.lang.reflect.Method;
public class MethodCall2 {
	public static void main(String[] args) throws Exception{
		PrivateClass pv = new PrivateClass();		
		Class clazz = pv.getClass();
		Object obj = clazz.newInstance();
		Method method = clazz.getDeclaredMethod("method1");
		method.setAccessible(true);
		method.invoke(obj);
	}
}

1. 클래스 정보 얻어오기

Private Method를 호출하기 위해서는 Spring의 정석에서 남궁성 선생님은 Class.forname()을 통해서 정보를 가져오셨는데, 약간 다른 방법을 생각해보다가 PrivateClass를 객체생성해서 Class타입의 clazz 변수에 getClass() 메서드를 이용해서 클래스 객체를 리턴받게 하였다.

2. 예외 던지기 및 클래스 객체 반환 받기

예외가 발생할 수 있으므로 throws Exception을 붙여주었고,
newInstance() 메서드는 반환타입이 Object이므로 Object타입의 참조변수 obj에 값을 저장해준다.

3. 메서드 정보 가져오기 & 메서드 사용 가능하게 설정하기

Method 타입의 참조변수 method에 Class의 getDeclareMethod() 메서드를 이용해서 "메서드이름"을 인자값으로 주면 참조변수 method에 메서드의 정보가 저장된다.
Method 클래스의 setAccessible() 메서드에 인자값으로 true를 주면 해당 메서드를 사용할 수 있도록 상태를 변경한것이다.

4. 메서드 실행

Method 클래스의 invoke() 메서드의 인자값으로 클래스의 정보를 가지고 있는 참조변수 obj의 값을 넣어주고 실행하면,

두..두둥 .. !!

output:

금기의 영역인줄 알았던 Private Method가 실행된다!
너무 신기해서 자주자주 활용해보려 했지만, 저렇게 Private Method를 끌어다가 쓰는 건 별로 좋지 않은 것이라고 한다.

2. Parameter가 있는 메서드 호출

import java.lang.reflect.Method;
public class MethodCall3 {
	public static void main(String[] args) throws Exception{		
		Class clazz = Class.forName("TJ5.PrivateClass");
		Object obj = clazz.newInstance();
		Method method = clazz.getDeclaredMethod("method2", int.class,int.class);
		method.setAccessible(true);
		method.invoke(obj, 4,2);
	}
}

1. 클래스 정보 얻어오기 & 클래스 객체 반환 받기

아까는 객체를 생성해서 getClass()로 정보를 얻어왔지만,
Class.forName()으로도 가능하다.. 하지만 forName() 메서드를 사용할 경우에는 패키지명.Class 형식을 지켜줘야 한다.
Object 타입의 obj 변수에 newInstance() 메서드로 클래스의 객체를 반환 받는 것 까지는 이전과 같다.

2. 예외 던지기 및 메서드 정보가져오기

예외가 발생할 수 있으므로 throws Exception을 붙여주었고,
Method타입의 method 변수에 getDeclaredMethod() 메서드를 이용하여 메서드의 정보를 가져왔다.
매개변수(Parameter)가 존재하는 메서드의 경우에는 getDeclaredMethod()의 인자 값으로,

2-1. Method의 이름, 매개변수의 타입1, 매개변수의 타입2

이런식으로 넣어주면 되는데, 매개변수의 타입은 문자열이면
String.class, 정수형이라면 int.class를 넣어주면 되고 나머지 기본자료형도 자료형.class 이런식으로 순서대로 나열해 주면 된다.

3. 메서드 사용가능하게 활성화 & 실행

위에서와 같이 setAccessible() 메서드에 true 인자값을 전달하여 메서드를 사용가능하게 해주고,
invoke() 메서드의 인자값으로 obj(클래스의 정보를 담고 있는 참조변수), 계산할 숫자1(정수형), 계산할 숫자1(정수형) 을 넣어주고 실행하면,

....!

이렇게 4와 2 가 a,b 값에 대입되서 계산이 이루어진뒤 출력 되는 것을 볼 수 있다.

간단하지만 신기했던 Reflection API의 기능을 써볼 수 있어서 재밌었다.

앞으로 더 많은 것들을 접하고 경험하는 시기가 왔으면 좋겠다 오늘도 화이팅 !

0개의 댓글