Skip to content

Latest commit

 

History

History
83 lines (70 loc) · 3.45 KB

아이템65.리플렉션보다는 인터페이스를 사용하라.md

File metadata and controls

83 lines (70 loc) · 3.45 KB

아이템65. 리플렉션보다는 인터페이스를 사용하라.

❓ Refletion

💡 구체적인 클래스 타입을 알지 못해도 그 클래스의 정보(메서드, 타입, 변수)에 접근할 수 있는 자바 API  
💡 Method.invoke는 어떤 클래스의 어떤 객체가 가진 어떤 메서드라도 호출할 수 있게 해줌. 리플렉션을 이용하면 컴파일 당시에 존재하지 않던 클래스도 이용할 수 있음.

🙅‍♀️ Reflection 단점

1. 컴파일 타임 타입 검사가 주는 이점을 하나도 누릴 수 없다.
2. 리플렉션을 이용하면 코드가 지저분하고 장황해진다.
3. 성능이 떨어진다.

🙆‍♀️ 리플렉션은 아주 제한된 형태로만 사용하자

    /* 방법 1. reflection API로 메소드를 호출하는 방식 👎 */
    // Node 클래스의 타입을 찾는다.
    Class<?> cls = Class.forName("Node");
    // Node 클래스의 생성자를 취득한다.
    Constructor<?> constructor = cls.getConstructor();
    // 생성자를 통해 newInstance 함수를 호출하여 Node 인스턴스를 생성한다.
    Object node = constructor.newInstance();
    // Node 클래스의 print함수를 취득한다. 
    Method method = cls.getMethod("print");
    // 취득한 함수에 생성한 인스턴스를 넣고 실행시킨다.
    method.invoke(node);

    /* 방법 2. 인터페이스를 참조하여 메소드를 호출 👍 */
    // 클래스 이름을 Class 객체로 변환
    Class<? extends Set<String>> cl = null;
    try {
        cl = (Class<? extends Set<String>>) Class.forName(args[0]); //비검사 형변환
    } catch (ClassNotFoundException e) {
        fatalError("클래스를 찾을 수 없습니다.");
    }
    
    // 생성자를 얻는다.
    Constructor<? extends Set<String>> cons = null;
    try {
        cons = cl.getDeclaredConstructor();
    } catch (NoSuchMethodException e) {
        fatalError("매개변수 없는 생성자를 찾을 수 없습니다.");
    }
     
    //집합의 인스턴스를 만든다.
    Set<String> s = null;
    try {
        s = cons.newInstance();
    } catch (IllegalAccessException e) {
        fatalError("생성자에 접근할 수 없습니다.");
    } catch (InstantiationException e) {
        fatalError("클래스를 인스턴스화할 수 없습니다.");
    } catch (InvocationTargetException e) {
        fatalError("생성자가 예외를 던졌습니다: " + e.getCause());
    } catch (ClassCastException e) {
        fatalError("Set을 구현하지 않은 클래스입니다.");
    }
    
    //생성한 집합을 사용한다.
    s.addAll(Arrays.asList(args).subList(1, args.length));
    System.out.println(s);

✔️ 실사용 예시

컴파일 당시에 컬럼명을 알 수 없을 때 사용..
ex) 타 시스템 인터페이스 시에 매칭되는 컬럼명을 코드로 관리함.

    Method getter = (new PropertyDescriptor(propertyName, obj.getClass(), "is" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1), (String)null)).getReadMethod();

    try {
        // 리플렉션 사용
        return getter.invoke(obj);
    } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException var9) {
        var9.printStackTrace();
    }


    // Client Code
    for(String col : cdMap.keySet()){
        cdNm = mdCdMap.getOrDefault(invokeGetter(dto, col), "");
        result.setCdNm(cdNm)
    }