[java] Java의 다른 클래스에서 개인 필드의 값을 읽는 방법은 무엇입니까?

제 3 자에 잘못 설계된 수업 JAR이 있으며 개인 분야 중 하나에 액세스해야 합니다. 예를 들어 왜 개인 필드를 선택해야합니까?

class IWasDesignedPoorly {
    private Hashtable stuffIWant;
}

IWasDesignedPoorly obj = ...;

리플렉션을 사용하여 값을 얻으려면 어떻게 stuffIWant해야합니까?



답변

개인 필드에 액세스하려면 클래스의 선언 된 필드 에서 가져 와서 액세스 할 수 있어야합니다.

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

편집 : aperkins 가 댓글을 달았 듯이 필드에 액세스하고 액세스 가능으로 설정하고 값을 검색하면 Exceptions 를 던질 수 있습니다 . 단지 확인 해야 할 예외는 위에 설명되어 있습니다.

NoSuchFieldException당신이 선언 된 필드에 해당하지 않은 이름으로 필드에 대한 요구한다면 던져 질 것이다.

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

IllegalAccessException분야에 액세스 할 수없는 있다면 비공개이며, 놓치고를 통해 액세스 가능하지 않은 경우 (예를 들어, 던져 질 것이다 f.setAccessible(true)선을.

RuntimeException발생 될 수 있습니다들 중 하나입니다 SecurityException(JVM의이 경우의 SecurityManager당신이 필드의 접근성을 변경할 수 없습니다), 또는 IllegalArgumentException당신이하지 필드의 클래스의 유형의 개체에 액세스에게 필드를 시도하고있는 경우, S :

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


답변

FieldUtilsApache Commons-lang3에서 시도하십시오 .

FieldUtils.readField(object, fieldName, true);


답변

리플렉션 만이 문제를 해결할 수있는 유일한 방법은 아닙니다 (클래스 / 컴포넌트의 개인 기능 / 행동에 액세스하는 것임)

다른 해결책은 .jar에서 클래스를 추출하고 Jode 또는 Jad를 사용하여 디 컴파일 하고 필드를 변경하거나 액세서를 추가 한 다음 원래 .jar에 대해 다시 컴파일하는 것입니다. 그런 다음 새 .class를 .jar클래스 경로 앞에 놓거나에 다시 삽입하십시오 .jar. jar 유틸리티를 사용하면 기존 .jar을 추출하고 다시 삽입 할 수 있습니다.

아래에 언급 된 것처럼, 이는 단순히 필드에 액세스 / 변경하는 것이 아니라 개인 상태에 액세스 / 변경하는 더 넓은 문제를 해결합니다.

이것은 필요 .jar하지 물론, 서명 할 수 있습니다.


답변

아직 언급되지 않은 다른 옵션 : Groovy 사용하십시오 . Groovy를 사용하면 언어 디자인의 부작용으로 프라이빗 인스턴스 변수에 액세스 할 수 있습니다. 현장에 게터가 있든 없든 상관없이

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


답변

Java 에서 Reflection을 사용하면 private/public한 클래스의 모든 필드와 메소드를 다른 클래스에 액세스 할 수 있지만 섹션 단점Oracle 문서 에 따라 다음과 같은 권장 사항이 있습니다.

“리플렉션을 사용하면 개인 필드 및 메소드에 액세스하는 것과 같이 비 반사 코드에서 불법적 인 작업을 코드에서 수행 할 수 있으므로 리플렉션을 사용하면 예기치 않은 부작용이 발생하여 코드가 제대로 작동하지 않아 이식성이 떨어질 수 있습니다. “추상화를 중단하고 플랫폼 업그레이드로 동작이 변경 될 수 있습니다.”

다음은 리플렉션의 기본 개념을 보여주는 코드 스냅 샷입니다.

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()));
        }
    }

}

그것이 도움이되기를 바랍니다.


답변

oxbow_lakes가 언급했듯이 리플렉션을 사용하여 액세스 제한을 피할 수 있습니다 (SecurityManager에서 허용한다고 가정).

즉,이 클래스가 너무 나쁘게 설계되어 해커에게 의지하게되면 대안을 찾아야 할 것입니다. 이 작은 해킹으로 인해 몇 시간이 절약 될 수 있지만 비용이 얼마나 들까 요?


답변

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

그을음은 Java로 완전히 작성되었으며 새로운 Java 버전에서 작동합니다.