KangMoo
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Java Reflection ![8u2qjz](https://hackmd.io/_uploads/HyOvOb6SC.jpg) ## 자바의 리플렉션(Reflection)이란? - 실행 중인 자바 애플리케이션 내부를 검사하고, 수정할 수 있는 강력한 기능 - 강력하다 = 큰 책임감이 따른다 - 클래스, 인터페이스, 메서드, 필드, 생성자 및 모듈과 같은 프로그램의 다양한 측면을 **런타임 중**에 검사하고 수정할 수 있는 기능을 제공한다 - 리플렉션을 사용할 경우 다음과 같은 이점을 얻을 수 있다 - 유연성 : 리플렉션을 사용하면 컴파일 시점에는 알 수 없는 클래스나 메소드에 대해 작업할 수 있게 함으로써 API 또는 프레임워크를 설계할 때 특히 유용하게 사용될 수 있다 - 결합도 감소 : 리플렉션은 클래스 간의 결합도를 낮출 수 있게 해주며, 이는 유지보수성과 확장성을 향상시킬 수 있다. - 동적인 기능 : 리플렉션을 통해 런타임에 동적으로 특정 기능을 수행하거나 변경하는 것이 가능해지며 동적 어플리케이션 개발에 필수적인 요소로 사용될 수 있다 ## 리플렉션은 언제 사용할까? 리플렉션을 주로 언제 사용하는지 알아보며 필요성을 느껴보자 - 프라이빗 메소드나 필드에 접근하여 조회하여 디버깅 및 테스트를 해야할 때 (ex. Junit) - 클래스의 속성, 메소드, 생성자 등에 대한 동적 타입 조사 및 조작이 필요한 경우 - 클래스 이름이나 구조를 동적으로 파악해야하는 경우 - DI(종속성 주입) 컨테이너 및 관점 지향 프로그래밍 시스템과 같은 프레임워크를 구현할 때 (ex. Spring Framework) - 어노테이션 정보를 런타임에 읽어서 특정 로직을 수행해야할 때 - 애플리케이션에 플러그인이나 확장 기능을 동적으로 로드하고 실행할 때 - 등등.. ## 리플렉션의 작동 원리 ![image](https://hackmd.io/_uploads/ByDyfYpS0.png) 자바 리플렉션 사용해보기 앞서 자바 리플렉션에 대한 원리를 이해해보자 1. 클래스 로딩 - 자바에서 모든 클래스는 사용되기 전에 클래스 로더에 의해 메모리에 로드된다 - 클래스 로더는 `.class` 파일(바이트코드)을 JVM 내부의 정의된 메모리 영역(메소드 영역)에 로드한다 - 이 과정에서 **클래스의 메타데이터(클래스 이름, 메소드, 필드 정보 등)가 메모리에 저장**된다 2. Class 객체 - JVM 내에 로드된 클래스마다 하나의 `java.lang.Class` 객체가 생성된다 - 이 `java.lang.Class` 객체는 로드된 클래스의 메타데이터를 가지고 있으며, 리플렉션은 이 `java.lang.Class` 객체를 사용하여 클래스의 정보를 조회하거나 조작한다 3. 리플렉션 API 사용 - `java.lang.Class` 는 해당 클래스의 메타데이터(예: 클래스 이름, 메소드, 필드 등)에 접근할 수 있도록 도와주는 API가 있으며, 리플렉션은 이 API를 이용한다 - 예를 들어, `getMethod()`, `getField()`, `getConstructor()` 등의 메소드를 통해 해당 클래스의 메소드, 필드, 생성자 정보를 조회할 수 있다 - 이러한 메소드들은 `java.lang.reflect` 패키지의 `Method`, `Field`, `Constructor` 등의 클래스를 반환한다 - 반환된 객체를 통해 메소드를 호출하거나, 필드의 값을 조회/수정할 수 있다 4. 동적 조작 - 리플렉션을 사용하면, 컴파일 시점에는 알 수 없었던 클래스의 이름이나 메소드를 실행 시점에 결정하고 조작할 수 있다 - 예를 들어, 문자열로 된 클래스 이름으로 `Class.forName()` 메소드를 호출하여 해당 클래스의 `Class` 객체를 얻을 수 있다 - 이를 통해 동적으로 객체를 생성하거나, 필드를 조회하거나 메소드를 호출하는 등의 작업을 수행할 수 있다 ## 리플렉션 사용해보기 ### 클래스 정보 얻기 리플렉션을 통해 다양한 방식으로 클래스의 정보를 가져올 수 있다 1. 객체를 통한 클래스 정보 얻기 ```java MyClass obj = new MyClass(); Class cls = obj.getClass(); ``` 2. 클래스 리터럴을 통한 클래스 정보 얻기 ```java Class cls = MyClass.class; ``` 3. 클래스 이름을 통해 클래스 정보 얻기 ```java Class cls = Class.forName("com.example.MyClass"); ``` ### 필드 정보 조회 및 조작 리플렉션을 통해 런타임에 객체의 필드(인스턴스 변수)에 접근하여 조회/수정 등이 가능하다 ```java import java.lang.reflect.Field; public class ReflectionExample { public static void main(String[] args) { try { // Person 객체 생성 Person person = new Person(); // Person 클래스의 Class 객체 가져오기 Class<?> clazz = person.getClass(); // 'name' 필드에 접근 Field nameField = clazz.getDeclaredField("name"); // private 필드 접근을 위해 접근성 변경 nameField.setAccessible(true); // 필드 값 읽기 System.out.println("기존 이름: " + person.getName()); // 필드 값 변경 nameField.set(person, "Alice"); // 변경된 필드 값 읽기 System.out.println("변경된 이름: " + person.getName()); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } static class Person { private String name = "Unknown"; public String getName() { return name; } } } ``` > **실행 결과** > > ```shell > 기존 이름: Unknown > 변경된 이름: Alice > ``` ### 생성자, 메서드 조회 및 사용 리플렉션을 통해 클래스의 생성자, 메서드를 조회/수정할 수 있다 ```java import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ReflectionDemo { public static void main(String[] args) { try { // Person 클래스의 Class 객체를 가져오기 Class<?> clazz = Class.forName("ReflectionDemo$Person"); // Person 클래스의 기본 생성자를 가져오기 Constructor<?> constructor = clazz.getConstructor(); // 생성자를 사용하여 Person 인스턴스를 생성 Object personInstance = constructor.newInstance(); // setName 메서드를 가져오기 Method setNameMethod = clazz.getMethod("setName", String.class); // setName 메서드를 실행 setNameMethod.invoke(personInstance, "Alice"); // getName 메서드를 가져오기 Method getNameMethod = clazz.getMethod("getName"); // getName 메서드를 실행하고 결과를 출력 System.out.println("Name: " + getNameMethod.invoke(personInstance)); } catch (Exception e) { e.printStackTrace(); } } static class Person { private String name; public Person() { this.name = "Unknown"; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } } } ``` > **실행 결과** > > ```shell > Name: Alice > ``` ### 리플렉션과 프록시를 사용한 메서드 조작 프록시(proxy)를 사용하여 메서드의 처리 로직이나 결과를 조작할 수 있다. 프록시는 Java 의 메서드 호출을 중간에 가로채고, 사용자 정의 로직으로 처리하거나 조작할 수 있게 해주는 기술이다 자바에서 프록시는 주로 인터페이스 기반의 동적 프록시(Dynamic Proxy)와, 클래스 기반의 프록시(CGLIB 등의 라이브러리를 사용) 두 가지 방법으로 구현되는데, 여기서는 Java의 내장 기능을 사용하는 인터페이스 기반의 동적 프록시에 대해 간단히만 알아본다 #### 동적 프록시의 사용법 1. 인터페이스 정의 2. `InvocationHandler` 구현 3. 프록시 객체 생성 및 사용 ```java import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyExample { public static void main(String[] args) { // 원래의 Person 객체 생성 Person realPerson = new PersonImpl("Alice"); // 프록시 객체 생성 Person proxyPerson = (Person) Proxy.newProxyInstance( Person.class.getClassLoader(), new Class<?>[] { Person.class }, new CustomInvocationHandler(realPerson) ); // 프록시 객체를 통한 getName 호출 System.out.println(proxyPerson.getName()); } interface Person { String getName(); } static class PersonImpl implements Person { private String name; public PersonImpl(String name) { this.name = name; } @Override public String getName() { return name; } } // InvocationHandler 구현 static class CustomInvocationHandler implements InvocationHandler { private final Object target; public CustomInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 메서드 호출 전에 할 작업 System.out.println("Before method: " + method.getName()); Object result = method.invoke(target, args); // 메서드 결과 조작 if (method.getName().equals("getName")) { result = "Hello, " + result + "!"; } // 메서드 호출 후에 할 작업 System.out.println("After method: " + method.getName()); return result; } } } ``` > **실행 결과** > > ```shell > Before method: getName > After method: getName > Hello, Alice! > ``` ### 리플렉션을 통한 어노테이션 조회 ```java import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; public class AnnotationReflectionExample { public static void main(String[] args) { try { // ExampleClass의 Class 객체를 가져온다 Class<?> clazz = ExampleClass.class; // 'exampleMethod' 메서드의 Method 객체를 가져온다 Method method = clazz.getMethod("exampleMethod"); // 해당 메서드에 적용된 MyAnnotation 어노테이션을 가져온다 if (method.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class); System.out.println("Value: " + myAnnotation.value()); } } catch (NoSuchMethodException e) { e.printStackTrace(); } } // 커스텀 어노테이션 정의 @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation { String value() default "Default Value"; } // ExampleClass 정의 static class ExampleClass { // 어노테이션 적용 @MyAnnotation(value = "Hello, Annotation!") public void exampleMethod() { } } } ``` > **실행 결과** > > ```shell > Value: Hello, Annotation! > ``` ## 리플렉션 사용 시 주의사항 리플렉션은 코드를 동적으로 코드를 조작할 수 있는 아주 강력한 기능이다. 당연히 강력한 기능인 만큼 사용 시 고려해야할 사항들이 많다 1. 성능 - 리플렉션을 통한 메서드 호출이나 필드 접근 방법은 일반적인 방법보다 느리므로 성능에 민감한 어플리케이션에서는 주의가 필요하다 - 리플렉션을 사용하면 컴파일러나 JVM이 코드에 대한 최적화를 하기가 어렵다 2. 보안 - 리플렉션을 사용하면 `private`, `protected`멤버에 접근할 수 있는데, 이는 캡슐화를 위반할 뿐더러 여러 보안 취약점을 초래할 수 있다 - 보안이 중요한 어플리케이션에서는 보안 관리자(Security Manager)를 사용하여 리플렉션 사용에 제한을 두는 것이 좋다 3. 유지보수 - 리플렉션을 사용한 코드는 직접적이지 않고 복잡할 수 있어, 코드의 가독성과 이해도를 저하시킨다 (위의 예시만 해도 한눈에 읽히지 않고 결과를 예측하기 어렵다) - 리플렉션은 중간에 코드를 조작해버릴 수 있으니 디버깅도 어렵게 만들 수 있다 ## 결론 리플렉션은 자바의 강력하면서도 유연한 기능 중 하나로, 클래스의 메타데이터에 접근하고, 런타임 중에 클래스의 행위를 조작할 수 있게 해준다. 이를 통해 개발자는 클래스의 내부 정보를 검사하고, 프라이빗 멤버에 접근하며, 유연하게 코드를 작성할 수 있게 된다. 리플렉션은 특히 API 및 프레임워크 개발, 플러그인 시스템, 테스트 코드 작성 등 다양한 상황에서 유용하게 활용될 수 있다. 하지만, 리플렉션은 그 사용에 있어서 신중함이 요구된다. 성능 저하, 보안 이슈, 유지보수의 어려움 등 리플렉션의 부작용도 고려해야 한다. 특히, 리플렉션은 캡슐화를 위반하고 코드의 명확성을 흐릴 수 있어, 이를 사용할 때는 해당 영역의 필요성과 효과를 면밀히 고려해야 한다. 최종적으로, 리플렉션은 자바 프로그래밍의 강력한 도구지만, 그 사용은 적절한 상황에서 신중하게 선택되어야 한다. 불필요하거나 과도한 리플렉션 사용은 애플리케이션의 성능과 안정성을 저해할 수 있으므로, 이점을 항상 염두에 두고 적절한 균형을 찾아야 한다.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully