java - type - 자바 리플렉션 메소드 호출




Java에서 다른 클래스의 private 필드 값을 읽는 방법? (7)

Soot Java Optimization 프레임 워크를 사용하여 바이트 코드를 직접 수정하십시오. http://www.sable.mcgill.ca/soot/

Soot는 Java로 작성되었으며 새로운 Java 버전으로 작동합니다.

제 3 자 JAR 에서 제대로 설계되지 않은 클래스가 있고 개인 필드 중 하나에 액세스해야합니다. 예를 들어 개인 필드를 선택해야하는 이유는 무엇입니까?

class IWasDesignedPoorly {
    private Hashtable stuffIWant;
}

IWasDesignedPoorly obj = ...;

stuffIWant 을 사용하여 stuffIWant 의 가치를 얻으려면 어떻게 stuffIWant 합니까?


Spring을 사용하는 경우, ReflectionTestUtils 는 최소한의 노력으로 여기서 도움이되는 편리한 도구를 제공합니다. 이는 "단위 및 통합 테스팅 시나리오에서 사용"으로 설명됩니다. ReflectionUtils 라는 비슷한 클래스가 있지만 이것은 "내부 용으로 만 의도 된 것" 으로 설명되어 있습니다. 이것이 의미하는 바를 해석 할 때이 대답 을 참조하십시오.

게시 된 예제를 해결하려면 다음을 수행하십시오.

Hashtable iWantThis = (Hashtable)ReflectionTestUtils.getField(obj, "stuffIWant");

다음을 수행해야합니다.

private static Field getField(Class<?> cls, String fieldName) {
    for (Class<?> c = cls; c != null; c = c.getSuperclass()) {
        try {
            final Field field = c.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field;
        } catch (final NoSuchFieldException e) {
            // Try parent
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "Cannot access field " + cls.getName() + "." + fieldName, e);
        }
    }
    throw new IllegalArgumentException(
            "Cannot find field " + cls.getName() + "." + fieldName);
}

리플렉션에 대한 추가 참고 사항 : 같은 이름을 가진 여러 클래스가 서로 다른 패키지에 존재하는 최상위 응답에 사용 된 리플렉션이 객체에서 올바른 클래스를 선택하지 못할 수도있는 특수한 경우가 있습니다. 따라서 객체의 package.class가 무엇인지 알면 다음과 같이 private 필드 값에 액세스하는 것이 좋습니다.

org.deeplearning4j.nn.layers.BaseOutputLayer ll = (org.deeplearning4j.nn.layers.BaseOutputLayer) model.getLayer(0);
Field f = Class.forName("org.deeplearning4j.nn.layers.BaseOutputLayer").getDeclaredField("solver");
f.setAccessible(true);
Solver s = (Solver) f.get(ll);

(이것은 나를 위해 일하지 않는 예제 클래스입니다)


비공개 필드에 액세스하려면 클래스의 선언 된 필드에서 비공개 필드를 가져 와서 액세스 가능하게해야합니다.

Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException

편집 : asperkins 에 의해 주석으로, 모두 액세스 할 수 및 값을 검색하는 모든 Exception throw합니다 필드를 액세스하는 경우에만 확인 된 예외를 염두해야 할 위의 설명되어 있습니다.

선언 필드에 대응하지 않는 이름의 필드를 요구했을 경우, NoSuchFieldException 가 Throw됩니다.

obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException

필드에 액세스 할 수없는 경우는, IllegalAccessException 가 Throw됩니다 (예를 들어, private이며 f.setAccessible(true) 행을 놓치지 않고 액세스 할 수 없게 된 f.setAccessible(true) .

throw 될 가능성이있는 RuntimeException 는, JVM의 SecurityManager 가 필드의 액세스 가능성을 변경할 수없는 경우, 또는 필드의 클래스의 형태가 아닌 객체의 필드에 액세스하려고하면, IllegalArgumentException 됩니다.

f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type

아직 언급되지 않은 다른 옵션 : Groovy를 사용하십시오. Groovy를 사용하면 언어 디자인의 부작용으로 사설 인스턴스 변수에 액세스 할 수 있습니다. 필드에 대한 getter가 있든 없든간에 사용할 수 있습니다.

def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()

Java Reflection을 사용하면 한 클래스의 모든 private/public 필드와 메소드를 다른 클래스에 액세스 할 수 있습니다. 단점 단원의 Oracle documentation 에 따라 다음을 권장합니다.

"리플렉션은 비공개 필드 및 메소드에 액세스하는 것과 같이 비 반사 코드에서 연산을 수행 할 수 있으므로 리플렉션을 사용하면 예기치 않은 부작용이 생길 수 있으며 이로 인해 코드 기능이 저하되고 이식성이 손상 될 수 있습니다. 추상화를 깨고 따라서 플랫폼 업그레이드로 동작을 변경할 수 있습니다. "

다음은 Reflection의 기본 개념을 설명하기위한 snapts 코드입니다.

Reflection1.java

public class Reflection1{

    private int i = 10;

    public void methoda()
    {

        System.out.println("method1");
    }
    public void methodb()
    {

        System.out.println("method2");
    }
    public void methodc()
    {

        System.out.println("method3");
    }

}

Reflection2.java

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


public class Reflection2{

    public static void main(String ar[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
    {
        Method[] mthd = Reflection1.class.getMethods(); // for axis the methods 

        Field[] fld = Reflection1.class.getDeclaredFields();  // for axis the fields  

        // Loop for get all the methods in class
        for(Method mthd1:mthd)
        {

            System.out.println("method :"+mthd1.getName());
            System.out.println("parametes :"+mthd1.getReturnType());
        }

        // Loop for get all the Field in class
        for(Field fld1:fld)
        {
            fld1.setAccessible(true);
            System.out.println("field :"+fld1.getName());
            System.out.println("type :"+fld1.getType());
            System.out.println("value :"+fld1.getInt(new Reflaction1()));
        }
    }

}

희망이 도움이 될 것입니다.





private