리플렉션 <2>

sungs·2025년 8월 22일

자바

목록 보기
72/95

메서드 탐색

리플렉션으로 메서드도 조회할 수 있다. Method[] methods = basicClass.getMethods(); 이런 방식으로 메서드를 담은 배열을 만든 다음 반복문으로 돌려서 출력하거나 사용하면 된다.

메서드를 조회하는 메서드로는 두 가지가 있는 geMethods와 getDeclaredMethods가 있다. 전자는 해당 클래스와 부모 클래스로부터 상속받은 모든 public 클래스를 반환하고, 후자는 해당 클래스의 private를 포함한 모든 메서드를 반환한다.

리플렉션을 사용하면 동적으로 메서드를 호출할 수 있다.

import java.lang.reflect.Method;
import java.util.Scanner;

/**
* 호출될 메서드들을 가지고 있는 대상 클래스
*/
class Bot {
   // String 타입의 인자를 받는 메서드
   public void greet(String name) {
       System.out.println("반갑습니다, " + name + "님! 🤖");
   }

   // int 타입의 인자를 받는 메서드
   public void setAlarm(int hour) {
       System.out.println("⏰ 알람이 " + hour + "시로 설정되었습니다.");
   }
   
   // 인자가 없는 메서드
   public void showStatus() {
       System.out.println("상태: 온라인 ✨");
   }
}

/**
* 메서드 이름과 인자를 입력받아 동적으로 호출하는 메인 클래스
*/
public class ArgumentScannerExample {
   public static void main(String[] args) {
       // 호출할 클래스의 인스턴스를 미리 생성
       Bot bot = new Bot();
       Scanner scanner = new Scanner(System.in);

       try {
           // 1. 사용자로부터 '메서드 이름' 입력받기
           System.out.print("호출할 메서드 이름을 입력하세요 (greet, setAlarm, showStatus): ");
           String methodName = scanner.nextLine();

           // 2. 사용자가 입력한 메서드에 따라 분기 처리
           switch (methodName) {
               case "greet": {
                   System.out.print("이름을 입력하세요: ");
                   String name = scanner.nextLine();
                   
                   // 메서드 정보 찾기 (메서드 이름, 파라미터 타입)
                   Method method = Bot.class.getMethod("greet", String.class);
                   // 메서드 호출 (인스턴스, 전달할 인자)
                   method.invoke(bot, name);
                   break;
               }
               case "setAlarm": {
                   System.out.print("시간(숫자)을 입력하세요: ");
                   int hour = scanner.nextInt();
                   scanner.nextLine(); // nextInt() 후의 줄바꿈 문자 제거

                   Method method = Bot.class.getMethod("setAlarm", int.class);
                   method.invoke(bot, hour);
                   break;
               }
               case "showStatus": {
                   Method method = Bot.class.getMethod("showStatus");
                   method.invoke(bot); // 인자 없이 호출
                   break;
               }
               default:
                   System.err.println("❗ 해당 이름의 메서드를 찾을 수 없습니다.");
                   break;
           }

       } catch (Exception e) {
           System.err.println("오류가 발생했습니다: " + e.getMessage());
       } finally {
           scanner.close();
       }
   }
}

스캐너를 활용해서 입력받고 getMehod로 메서드를 찾고 invoke로 메서드를 동적으로 호출할 수 있다. 여기서 private까지 접근하려면 setAccessible(true)를 사용하면 된다.

동적으로 호출할 수 있다는 건 값이 변경될 수 있다는 것이다. 여기서도 메서드 이름을 변수로 사용해 스캐너로 입력 받았기 때문에 호출되는 메서드는 변경될 수 있다. 반대로 정적으로 호출했다는 건 일반적으로 객체 생성하고 객체.메서드 이런 형식으로 호출하는 것으로 개발자가 직접 바꾸지 않는 이상 그 줄의 값은 바뀌지 않는 것을 말한다.

하지만 private에 접근하는 건 캡슐화를 꺠드리므로 웬만해선 사용하지 말아야 한다. 리플렉션을 주로 사용하는 곳은 일반적인 비즈니스 로직이 아니다. 라이브러리나 테스트, 혹은 null 값이 생기면 절대 안 될 때 같은 여러 클래스에서 공통으로 무언가를 할 때 사용해야 한다.

profile
앱 개발 공부 중

0개의 댓글