본문 바로가기
  • 개발공부 및 일상적인 내용을 작성하는 블로그 입니다.
부트캠프/후기 챌린지

[멋쟁이사자처럼부트캠프] 백엔드 자바 21기 (2026.01.22)

by 방구석 취준생 2026. 3. 23.

* 해당 글은 백엔드 자바 강의이후 회고 글입니다.

https://bootcamp.likelion.net/school/kdt-backendj-21th

 

백엔드 부트캠프 21기: Java : 멋사 부트캠프

실전 스킬 기반 백엔드 개발자 취업 완벽 대비 교육

bootcamp.likelion.net

 

자바 리플렉션(Reflection)

- 객체를 통해 클래스의 설계 정보를 확인하는 기술

리플렉션(reflection) 은 구체적인 클래스 타입을 알지 못하더라도 그 클래스의 메서드,타입, 변수들에 접근할 수 있도록 해주는 자바 API 를 말하며 컴파일 시간이 아닌 실행 시간에 동적으로 특정 클래스의 정보를 추출할 수 있는 프로그래밍 기법이라 할 수 있다.
즉, 객체 필드에 메모리가 할당되는 동적 바인딩 타이밍의 시점에 맞춰 해당 객체에 대한 설계 정보를 확인할 수 있는 기술이라고 볼 수 있다. (java.lang.reflect API 클래스 사용)

* 보안 이슈, 컴파일 시점 타입 체크 불가능등을 주의한다.

* 접근 제한자 무시(setAccessible) : 리플렉션을 사용하면 접근 제한자를 무시할 수 있다.

Field field = clazz.getDeclaredField("age");
field.setAccessible(true); // private 필드/메서드 접근 가능, 프레임워크 내부 동작의 핵심

 

리플렉션이 활용되는 시점

  • 동적으로 클래스를 사용해야 할 때 사용한다. 다시 말해, 작성 시점에서는 어떠한 클래스를 사용할 지 모르지만 런타임 시점에서 객체를 가져와 실행해야 하는 경우 필요하다.
  • 프레임워크나 IDE에서 이런 동적 바인딩을 이용한 기능을 제공한다.
    • 예시 1. Spring framework : @Service, @Autowired 같은 어노테이션이 붙은 클래스를 찾아 자동으로 객체를 생성하고 의존성을 주입할 때 사용
    • 예시 2. Jackson/Gson : JSON 데이터를 자바 객체로 변환할 때, 객체의 필드 이름을 리플렉션으로 읽어 매핑
    • 예시 3. JUnit : @Test 가 붙은 메서드들을 찾아 자동 실행
    • 예시 4. IDE(IntelliJ, Eclipse) : 코드 자동완성 기능을 제공할 때 해당 클래스의 메서드 목록 리턴 및 호출

 

리플렉션을 사용하여 가져올 수 있는 정보

  • Class
  • Constructor
  • Method
  • Field

Class 클래스

자바의 모든 클래스와 인터페이스는 컴파일되고 나면 class 파일로 생성된다.

이 class 파일에는 클래스나 인터페이스에 대한 변수, 메서드, 생성자 등의 정보가 들어있다.

Class 클래스는 컴파일된 class 파일에 저장된 클래스나 인터페이스 정보를 가져오는데 사용한다.

  • 개발을 하다보면 여러 클래스 중에 상황에 따라 다른 클래스를 사용해야 할 때도 있고, 반환받는 클래스가 정확히 어떤 자료형인지 모를 때도 있다.
  • 이렇게 모르는 클래스의 정보를 사용할 경우에 클래스 정보를 직접 찾아보아야 한다. 이때 Class 클래스를 활용할 수 있다.
  • Class 클래스를 선언하고 클래스 정보를 가져오는 방법은 다음과 같다.
String s = new String();
// 동적 객체생성
Class<?> clazz = s.getClass();
Class<?> clazz = Class.forName(java.lang.String);
// 컴파일 시점에 클래스 타입을 몰라도 객체 생성이 가능하다. Spring IoC, Factory 패턴의 핵심원리.

Object obj = clazz.getDeclaredConstructor().newInstance();

 

간단하게 한번 활용해보자.

 

- Person.java

package classex;

public class Person {
    private String name;
    private int age;
    
    public Person() {}
    
    public Person(String name) {
        this.name = name;
    }
    
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name){
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age){
        this.age
    }
}

 

위와같이 만들어둔 Person 클래스의 Class 클래스를 가져와보자.

- ClassTest.java

package classex;

public class ClassTest {
    // forName() 메서드에서 발생하는 예외를 처리함 
    // 이름과 일치하는 클래스가 없는 경우 ClassNotFoundException 발생
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Person();
        Class pClass1 = person.getClass(); // Object 의 getClass() 메서드 사용
        System.out.println(pClass.getName());
        
        Class pClass2 = Person.class; // 직접 class 파일 대입하기
        System.out.println(pClass2.getName());
        
        Class pClass3 = Class.forName("classex.Person"); // 클래스 이름으로 가져오기
        System.out.println(pClass3.getName());
    }
}

 

  • forName() 메서드를 통해 클래스 이름으로 정보를 가져오는 경우 매개변수로 쓰이는 값은 문자열이다. 이때 매개변수로 받은 문자열에 해당하는 클래스가 존재하지 않으면 클래스를 가져오는데 실패하여 ClassNotfoundException 이 발생한다.
  • Class 를 가져온 후 getName() 메서드를 호출하면 클래스의 이름인 classex.Person 이 잘 출력되는 것을 확인해볼 수 있다.

Class 클래스를 활용해 클래스 정보 알아보기

  • 내 컴퓨터에 저장되어 있지 않은 객체를 메모리에 로드하고 생성하는 경우 그 객체의 정보를 알 수 없다.
  • 이때 Class 클래스를 가져올 수 있다면 해당 클래스 정보, 즉 생성자, 메서드, 멤버 변수 정보를 찾을 수 있다.
  • 이렇게 사용하려는 클래스의 자료형을 모르는 상태에서 Class 클래스를 활용하여 그 클래스의 정보를 가져오고, 이 정보를 활용하여 인스턴스를 생성하거나 메서드를 호출하는 방식을 리플렉션(reflection) 이라고 한다.

아래의 예제를 통해 정보를 어떻게 찾아오는지 알아보자.

아래 예제에서 사용되는 Constructor, Method, Field 등의 클래스는 java.lang.reflect 패키지에 정의되어 있다.

Class 클래스와 java.lang.reflect 패키지의 클래스를 사용하면 리플렉션 프로그래밍을 할 수 있다.

 

- StringClassTest.java

package classes;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class StringClassTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Class strClass = Class.forName("java.lang.String"); // 클래스 이름으로 가져오기
        
        Constructor[] cons = strClass.getConstructors(); // 모든 생성자 가져오기
        for(Constructor c : cons) {
            System.out.println(c);
        }
        
        System.out.println();
        Field[] fields = strClass.getFields(); // 모든 멤버변수(필드) 가져오기
        for(Field f : fields) {
            System.out.println(f);
        }
        
        System.out.println();
        Method[] methods = strClass.getMethods(); // 모든 메서드 가져오기
        for(Method m : methods) {
            System.out.println(m);
        }
    }
}

 

  • String 클래스의 모든 생성자를 가져오기 위해 Class 클래스의 getConstructors() 메서드를 호출했다.
  • 필드와 메서드 정보또한 마찬가지로 각각 Class 클래스의 getFields(), getMethods() 메서드를 호출하여 가져올 수 있다.
  • 이와 같이 java.lang.reflect 패키지에 있는 클래스를 활용하면 클래스의 이름만 알아도 클래스의 생성자, 메서드 등의 정보를 알 수 있다.

접근 제한자 무시 : setAccessible

리플렉션을 사용하면 접근 제한자를 무시할 수 있다.

아래의 코드를 보자.

class My {
    // setAccessible() 메서드 테스트를 위한 클래스 생성
    private String name = "홍길동";
    private int age = 20;
}

public class b_reflect {
    public static void main(String[] args){
        My my = new My(); 
        Class<?> res = my.getClass();
        
        // 필드 정보를 확인
        System.out.println("\n\n 1. 필드의 정보");
        for(Field field : res.getDeclaredFields()){
            System.out.println(" - " + field);
        }
        
        // 필드값 초기화
        Field field = null;
        
        // private String name 필드값 접근제한 무시 및 변경 시작
        try{
            field = res.getDeclaredField("name");
        } catch(NoSuchFieldException | SecurityException e) {
            e.printStackTrace();
        }
        
        field.setAccessible(true); // private 필드 접근제한 무시
        
        try {
            field.set(my, "정길동"); // 필드값 변경
            System.out.println(field.get(my));
        } catch(IllegalArgumentException | IllegalAccessException e){
            e.printStackTrace();
        }
        
        // private int age 필드값 접근제한 무시 및 변경 시작
        try{
            field = res.getDeclaredField("age");
        } catch(NoSuchFieldException | SecurityException e){
            e.printStackTrace();
        }
        field.setAccessible(true); // private 필드 접근제한 무시
        
        try{
            field.set(my, 100);
            System.out.println((field.getInt(my) + 100) + " ," + field.getByte(my));
        } catch(IllegalArgumentException | IllegalAccessException) {
            e.printStackTrace();
        }
    }
}

 

 

  • 위의 코드는 My 클래스 내부에 선언된 private 필드들에 대해 setAccessible(true) 를 통해 접근제한을 무시한 후 값을 리플렉션을 통해 변경시키는 클래스이다.
  • 코드를 자세히 보면 리플렉션 객체 field 에 대해 setAccessible(true) 를 통해 private 필드에 대한 접근제한을 무시한 후 set() 메서드를 통해 해당 필드의 값을 변경시키는 것을 알 수 있다.

참조 : https://jeongkyun-it.tistory.com/225

 

[Java] 리플렉션 (Reflection)이란 무엇일까? (개념/ 예시)

서론 이번 포스팅에서 다룰 내용은 '리플렉션'이다. 최근 "리플렉션이 무엇인가요?" 라는 질문을 받았는데, 제대로 된 답변을 못한 것 같다. C# 개발을 할 때 분명 사용은 해보았지만 개념적으로

jeongkyun-it.tistory.com