Skip to content

Latest commit

Β 

History

History
228 lines (162 loc) Β· 8.2 KB

reflection.md

File metadata and controls

228 lines (162 loc) Β· 8.2 KB

λͺ©μ°¨



κ°œμš”

λ¦¬ν”Œλ ‰μ…˜μ€ μžλ°”μ˜ μ—¬λŸ¬ νŠΉμ§•μ€‘ ν•˜λ‚˜λ‹€. (C, C++와 같은 μ–Έμ–΄λŠ” 가지고 μžˆμ§€ μ•ŠλŠ” νŠΉμ§•μ€‘ ν•˜λ‚˜μ΄κΈ°λ„ ν•˜λ‹€.)

λ¦¬ν”Œλ ‰μ…˜μ„ μ‚¬μš©ν•˜λ©΄ μ‹€ν–‰ 쀑인 μžλ°” ν”„λ‘œκ·Έλž¨μ„ 자체적으둜 κ²€μ‚¬ν•˜κ±°λ‚˜ λ‚΄λΆ€ 속성듀을 μ‘°μž‘ν•  수 μžˆλ‹€.

λ˜ν•œ, λ¦¬ν”Œλ ‰μ…˜μ„ 톡해 μΈμŠ€ν„΄μŠ€ 생성, λ©”μ„œλ“œ μ‹€ν–‰, ν•„λ“œ 쑰회 및 μˆ˜μ • λ“±λ“± μ—¬λŸ¬ μ‘°μž‘μ„ ν•  수 μžˆλ‹€.

μ‹€μ œλ‘œ μŠ€ν”„λ§(DI, Component Scan, ...)와 μ—¬λŸ¬ 라이브러리(Object Mapper, ...)μ—μ„œ λ¦¬ν”Œλ ‰μ…˜μ„ 잘 ν™œμš©ν•˜κ³  μžˆλ‹€.

이번 글에선 λ¦¬ν”Œλž™μ…˜μ΄λž€ 무엇이며, μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λŠ”μ§€μ— λŒ€ν•΄μ„œ λ‹€λ€„λ³΄κ³ μž ν•œλ‹€.


java.lang.Class<T>

λ¦¬ν”Œλ ‰μ…˜μ— λŒ€ν•΄μ„œ 닀루기 전에 κ°€μž₯ λ¨Όμ € μ•Œμ•„μ•Ό ν•˜λŠ” ν΄λž˜μŠ€κ°€ μžˆλ‹€. λ°”λ‘œ java.lang.Class<T>이닀.

λ¦¬ν”Œλ ‰μ…˜μ€ Class<T>λ₯Ό ν†΅ν•΄μ„œ λ™μž‘ν•œλ‹€.


πŸ€” Class<T>

  • Class ν΄λž˜μŠ€λŠ” μžλ°” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ λ™μž‘ν•˜λŠ” λͺ¨λ“  ν΄λž˜μŠ€μ™€ μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν‘œν˜„ν•˜λŠ” ν΄λž˜μŠ€μ΄λ‹€.
    • μžλ°” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ λŒμ•„κ°€λŠ” λͺ¨λ“  것은 ν΄λž˜μŠ€μ— μ†ν•œλ‹€.
      • enum, annotation은 μΈν„°νŽ˜μ΄μŠ€
      • λ°°μ—΄κ³Ό κΈ°λ³Έ μžλ£Œν˜• λͺ¨λ‘ Class둜 ν‘œν˜„λœλ‹€.

❗️ Class<T>λŠ” public μƒμ„±μžκ°€ μ—†λ‹€.

  • κ·Έ μ΄μœ λŠ” μ‚¬μš©μžκ°€ Classλ₯Ό μΈμŠ€ν„΄μŠ€ν™”ν•˜μ§€ μ•Šκ³ , JVM이 μΈμŠ€ν„΄μŠ€ν™”ν•΄μ£ΌκΈ° λ•Œλ¬Έμ΄λ‹€.
    • 더 μ •ν™•νžˆλŠ” JVM의 클래슀 λ‘œλ”κ°€ λ°”μ΄νŠΈ μ½”λ“œ(.class)λ₯Ό 읽고 λ‘œλ”© 단계가 λλ‚˜λ©΄ ν•΄λ‹Ή 클래슀 νƒ€μž…μ˜ Class객체λ₯Ό μƒμ„±ν•˜μ—¬ Heap μ˜μ—­μ— μ €μž₯ν•œλ‹€.
    • JVMμ—μ„œ defineClassλΌλŠ” λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μƒμ„±ν•œλ‹€κ³  ν•œλ‹€.

클래슀 정보 쑰회

ν΄λž˜μŠ€μ— λŒ€ν•œ 정보λ₯Ό κ°€μ Έμ˜€κΈ° μœ„ν•΄μ„  Class<T>λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.


Class<T> μ ‘κ·Ό

μžλ°” λŸ°νƒ€μž„λ•Œ Class<T>λŠ” μ–΄λ–»κ²Œ κ°€μ Έμ˜¬ 까?

  1. νƒ€μž….class
    • λͺ¨λ“  ν΄λž˜μŠ€λŠ” JVM을 톡해 λ‘œλ”©λœ ν›„ Class객체λ₯Ό μƒμ„±ν•œλ‹€. κ·ΈλŸ¬λ―€λ‘œ, νƒ€μž….classλ₯Ό 톡해 μ ‘κ·Όν•  수 μžˆλ‹€.
  2. getClass()
    • λͺ¨λ“  클래슀의 μΈμŠ€ν„΄μŠ€λŠ” getClass()λ₯Ό 가지고 μžˆλ‹€. 즉, λͺ¨λ“  μΈμŠ€ν„΄μŠ€λ₯Ό 톡해 ν•΄λ‹Ή 클래슀λ₯Ό μ ‘κ·Όν•  수 μžˆλ‹€.
  3. Class.forName("FQCN")
    • 클래슀 이름(Fully Qualified Class Name)을 톡해 가지고 올 수 μžˆλ‹€.
    • μ°ΎλŠ” ν΄λž˜μŠ€κ°€ μ—†μœΌλ©΄ ClassNotFoundException이 던져짐.

Class<T>λ₯Ό 톡해 정보 쑰회

Class<T>λ₯Ό ν†΅ν•΄μ„œ ν΄λž˜μŠ€μ— λŒ€ν•œ 정보λ₯Ό κ°€μ Έμ˜¬ 수 μžˆλ‹€.

ν•„λ“œ, λ©”μ„œλ“œ, μƒμœ„ 클래슀, μΈν„°νŽ˜μ΄μŠ€, μ• λ…Έν…Œμ΄μ…˜, μƒμ„±μž λ“±λ“± λͺ¨λ‘ κ°€μ Έμ˜¬ 수 μžˆλ‹€.

보톡 λ‹€ getXXX을 톡해 κ°€μ Έμ˜€λ©°, μ•„λž˜μ™€ 같은 νŠΉμ§•μ΄ μžˆλ‹€.

  • getXXX()와 getDeclaredXXX()
    • getXXX()λŠ” public만 κ°€μ Έμ˜¬ 수 μžˆλ‹€. name을 ν†΅ν•œ 검색도 λ™μΌν•˜λ‹€.
    • getDeclaredXXX()λŠ” μ ‘κ·Ό μ œμ–΄μžμ™€ 상관없이 λͺ¨λ“  속성과 λ©”μ„œλ“œλ₯Ό κ°€μ Έμ˜¬ 수 μžˆλ‹€.
  • μ ‘κ·Ό μ œμ–΄μž - Modifier
    • μ ‘κ·Ό μ œμ–΄μžκ°€ 뢙을 수 μžˆλŠ” 정보(ex. ν•„λ“œ, λ©”μ„œλ“œ...)λŠ” λͺ¨λ‘ Modifierλ₯Ό 가진닀.
    • Modifierλ₯Ό ν†΅ν•΄μ„œ μ ‘κ·Ό μ œμ–΄μžκ°€ 무엇인지 μ•Œ 수 μžˆλ‹€.
    • ex. isPrivate(field.getModifier())

μ• λ…Έν…Œμ΄μ…˜κ³Ό λ¦¬ν”Œλ ‰μ…˜

λ¦¬ν”Œλ ‰μ…˜μ„ 톡해 μ• λ…Έν…Œμ΄μ…˜μ„ 닀루기 μœ„ν•΄μ„  λͺ‡ 가지 더 μ•Œμ•„μ•Ό ν•˜λŠ” 뢀뢄이 μžˆλ‹€.

μš°μ„  μ• λ…Έν…Œμ΄μ…˜μ„ μœ„ν•œ 속성 μ• λ…Έν…Œμ΄μ…˜μ΄λ‹€.

  • @Retention: ν•΄λ‹Ή μ• λ…Έν…Œμ΄μ…˜μ„ μ–Έμ œκΉŒμ§€ μœ μ§€ν•  것인지? ex. RetentionPolicy.SOURCE(μ½”λ“œ), CLASS(λ°”μ΄νŠΈμ½”λ“œ), RUNTIME(λŸ°νƒ€μž„)
  • @Inherit: ν•΄λ‹Ή μ• λ…Έν…Œμ΄μ…˜μ„ ν•˜μœ„ ν΄λž˜μŠ€κΉŒμ§€ 전달할 것인지? 이 μ• λ…Έν…Œμ΄μ…˜μ„ 뢙여진 클래슀의 ν•˜μœ„ ν΄λž˜μŠ€κΉŒμ§€ 이 μ• λ…Έν…Œμ΄μ…˜μ΄ 뢙은 것 처럼 λ™μž‘ν•œλ‹€.
  • @Target: ν•΄λ‹Ή μ• λ…Έν…Œμ΄μ…˜μ„ 어디에 μ‚¬μš©ν•  수 μžˆλŠ”μ§€? ex. ElementType.FIELD, ElementType.METHOD...

μžμ„Έν•œ μ• λ…Έν…Œμ΄μ…˜ μ‚¬μš©λ²•μ€ μ—¬κΈ°μ„œ 확인가λŠ₯ν•˜λ‹€.


또 ν•˜λ‚˜ μ€‘μš”ν•œ 점은 @Inherit에 λ”°λ₯Έ μ‘°νšŒλ‹€.

  • getAnnotation(): 상속받은 (@Inherit)μ• λ…Έν…Œμ΄μ…˜κΉŒμ§€ μ‘°νšŒλœλ‹€.
  • getDeclaredAnnotations(): 자기 μžμ‹ μ—λ§Œ λΆ™μ–΄μžˆλŠ” μ• λ…Έν…Œμ΄μ…˜μ„ μ‘°νšŒλœλ‹€.

μΈμŠ€ν„΄μŠ€ 생성 및 정보 μˆ˜μ •

λ¦¬ν”Œλ ‰μ…˜μ„ 톡해 Class<T>λ₯Ό μΈμŠ€ν„΄μŠ€ν™”ν•  μˆ˜λ„ μžˆλ‹€.

두 가지 방법이 μ‘΄μž¬ν•œλ‹€.

  1. Class.newInstance() -> ν˜„μž¬ deprecatedλ˜μ–΄μ„œ ꢌμž₯ν•˜μ§€ μ•ŠλŠ”λ‹€. (μ‚¬μš©μ‹œ μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€.)
  2. μƒμ„±μžλ₯Ό ν†΅ν•œ 생성 -> ꢌμž₯ν•˜λŠ” μΈμŠ€ν„΄μŠ€ λ§Œλ“œλŠ” 방법이닀.

κ°„λ‹¨ν•œ μ˜ˆμ‹œλ₯Ό 톡해 μ‚΄νŽ΄λ³΄μž.

public class User {

    private String name;

    private int age;

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter / setter
}


@Test
void μƒμ„±μžλ₯Ό_ν†΅ν•œ_μΈμŠ€ν„΄μŠ€_λ§Œλ“€κΈ°()
    throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
    // given
    Class<?> classOfUser = User.class;

    // when
    // String을 λ§€κ°œλ³€μˆ˜λ‘œ 가진 가진 μƒμ„±μž κ°€μ Έμ˜΄.
    Constructor<?> constructor = classOfUser.getConstructor(String.class);
    User user = (User) constructor.newInstance("binghe");

    // private Field μ ‘κ·Ό ν›„ μˆ˜μ •
    Field age = classOfUser.getDeclaredField("age"); // ν•„λ“œ μ ‘κ·Ό
    age.setAccessible(true);
    age.set(user, 10);                              // ν•„λ“œ μˆ˜μ •(λ³€κ²½ν•˜κ³ μž ν•˜λŠ” 객체, κ°’)

    // then
    assertThat(user.getName()).isEqualTo("binghe");
    assertThat(user.getAge()).isEqualTo(10);
}
  • ν•„λ“œ κ°’ μ ‘κ·Ό 및 μ„€μ •ν•˜κΈ°
    • νŠΉμ • μΈμŠ€ν„΄μŠ€κ°€ 가지고 μžˆλŠ” 값을 κ°€μ Έμ˜€κ³  μˆ˜μ •ν•˜λŠ” 것이기 λ•Œλ¬Έμ— μΈμŠ€ν„΄μŠ€κ°€ ν•„μš”ν•¨.
    • ν•„λ“œ μ ‘κ·Ό: Field.get(object)
    • ν•„λ“œ μˆ˜μ •: Field.set(object, value)
      • Static ν•„λ“œλŠ” κ°€μ Έμ˜¬ λ•Œ μΈμŠ€ν„΄μŠ€(object)κ°€ ν•„μš” μ—†κΈ° λ•Œλ¬Έμ— null을 λ„˜κΈ°λ©΄ λœλ‹€.

클래슀 정보 μ‹€ν–‰

λ§ˆμ§€λ§‰μœΌλ‘œ λ¦¬ν”Œλž™μ…˜μ„ 톡해 λ©”μ„œλ“œ 싀행을 ν•΄λ³΄μž.

Object Method.invoke(object, params);

public class User {

    private String name;

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    public String sayHi() {
        return "hi";
    }
}

@Test
void λ©”μ„œλ“œ_μ‹€ν–‰()
    throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    // given
    Class<?> classOfUser = User.class; 

    // when
    // 객체 생성
    Constructor<?> constructor = classOfUser.getConstructor(String.class);
    User user = (User) constructor.newInstance("binghe");

    // λ©”μ„œλ“œ 뢈러였기
    Method sayHi = classOfUser.getMethod("sayHi");

    // then
    // λ©”μ„œλ“œ μ‹€ν–‰ 및 ν…ŒμŠ€νŠΈ
    assertThat(sayHi.invoke(user)).isEqualTo("hi");
}

λ¦¬ν”Œλ ‰μ…˜ 단점과 μ£Όμ˜ν•  점

μ•„λž˜ λ¬Έμ œμ μ€ 잘λͺ» μ‚¬μš©ν•  κ²½μš°μ—λ§Œ ν•΄λ‹Ήλœλ‹€. 잘 μ‚¬μš©ν•˜λ©΄ κ°•λ ₯ν•œ κΈ°λŠ₯이닀!

  1. μ§€λ‚˜μΉœ μ‚¬μš©μ€ μ„±λŠ₯ 이슈λ₯Ό μ•ΌκΈ°ν•  수 μžˆλ‹€.
    • λ°˜λ“œμ‹œ ν•„μš”ν•œ κ²½μš°μ—λ§Œ μ‚¬μš©ν•  것은 μΆ”μ²œν•œλ‹€.
  2. 컴파일 νƒ€μž„μ— ν™•μΈλ˜μ§€ μ•Šκ³  λŸ°νƒ€μž„ μ‹œμ—λ§Œ λ°œμƒν•˜λŠ” 문제λ₯Ό λ§Œλ“€ κ°€λŠ₯성이 μžˆλ‹€.
  3. μ ‘κ·Ό μ§€μ‹œμžλ₯Ό μ˜λ„μ μœΌλ‘œ λ¬΄μ‹œν•  수 있기 λ•Œλ¬Έμ— μžμΉ«ν•˜λ©΄ λ³΄μ•ˆμ  μ΄μœ κ°€ λ°œμƒν•  수 μžˆλ‹€.

μ°Έκ³