문제

XML과 리플렉션을 사용하여 반환하는 클래스가 있습니다. Object다른 수업으로 가요.

일반적으로 이러한 객체는 외부 객체의 하위 필드이지만 때로는 즉시 생성하고 싶은 경우도 있습니다.나는 이와 같은 것을 시도했지만 아무 소용이 없었습니다.나는 Java가 당신의 접근을 허용하지 않기 때문이라고 생각합니다. private 반성을 위한 방법.

Element node = outerNode.item(0);
String methodName = node.getAttribute("method");
String objectName = node.getAttribute("object");

if ("SomeObject".equals(objectName))
    object = someObject;
else
    object = this;

method = object.getClass().getMethod(methodName, (Class[]) null);

제공된 방법이 다음과 같은 경우 private, 다음과 같이 실패합니다. NoSuchMethodException.방법을 만들어서 해결할 수 있었는데 public, 또는 파생할 다른 클래스를 만드는 것입니다.

간단히 말해서, 액세스할 수 있는 방법이 있는지 궁금합니다. private 반사를 통한 방법.

도움이 되었습니까?

해결책

반사로 개인 방법을 호출 할 수 있습니다. 게시 된 코드의 마지막 비트 수정 :

Method method = object.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
Object r = method.invoke(object);

몇 가지 경고가 있습니다. 첫 번째, getDeclaredMethod 현재에서 선언 된 메소드 만 찾을 수 있습니다 Class, 수퍼 타입에서 상속되지 않습니다. 따라서 필요한 경우 콘크리트 클래스 계층을 가로 지르십시오. 둘째, a SecurityManager 사용을 방지 할 수 있습니다 setAccessible 방법. 따라서 a로 실행해야 할 수도 있습니다 PrivilegedAction (사용 AccessController 또는 Subject).

다른 팁

사용 getDeclaredMethod() 개인 메소드 객체를 얻은 다음 사용합니다 method.setAccessible() 실제로 그것을 부를 수 있습니다.

이 메소드가 비 프리맨티 데이터 유형을 수락하는 경우 다음 방법을 사용하여 모든 클래스의 개인 메소드를 호출 할 수 있습니다.

public static Object genericInvokeMethod(Object obj, String methodName,
            Object... params) {
        int paramCount = params.length;
        Method method;
        Object requiredObj = null;
        Class<?>[] classArray = new Class<?>[paramCount];
        for (int i = 0; i < paramCount; i++) {
            classArray[i] = params[i].getClass();
        }
        try {
            method = obj.getClass().getDeclaredMethod(methodName, classArray);
            method.setAccessible(true);
            requiredObj = method.invoke(obj, params);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return requiredObj;
    }

허용되는 매개 변수는 OBJ, MethodName 및 매개 변수입니다. 예를 들어

public class Test {
private String concatString(String a, String b) {
    return (a+b);
}
}

메소드 동시 조정은 다음과 같이 호출 할 수 있습니다

Test t = new Test();
    String str = (String) genericInvokeMethod(t, "concatString", "Hello", "Mr.x");

Spring의 반사석을 사용 하여이 작업을 수행 할 수 있습니다 (org.springframework.test.util.reflectiontestutils)

ReflectionTestUtils.invokeMethod(instantiatedObject,"methodName",argument);

예 : 개인 방법이있는 수업이있는 경우 square(int x)

Calculator calculator = new Calculator();
ReflectionTestUtils.invokeMethod(calculator,"square",10);

리플렉션을 통해 보호된 메서드를 실행하기 위한 완전한 코드를 제공하겠습니다.제네릭, 자동 박싱된 매개변수 및 null 값을 포함한 모든 유형의 매개변수를 지원합니다.

@SuppressWarnings("unchecked")
public static <T> T executeSuperMethod(Object instance, String methodName, Object... params) throws Exception {
    return executeMethod(instance.getClass().getSuperclass(), instance, methodName, params);
}

public static <T> T executeMethod(Object instance, String methodName, Object... params) throws Exception {
    return executeMethod(instance.getClass(), instance, methodName, params);
}

@SuppressWarnings("unchecked")
public static <T> T executeMethod(Class clazz, Object instance, String methodName, Object... params) throws Exception {

    Method[] allMethods = clazz.getDeclaredMethods();

    if (allMethods != null && allMethods.length > 0) {

        Class[] paramClasses = Arrays.stream(params).map(p -> p != null ? p.getClass() : null).toArray(Class[]::new);

        for (Method method : allMethods) {
            String currentMethodName = method.getName();
            if (!currentMethodName.equals(methodName)) {
                continue;
            }
            Type[] pTypes = method.getParameterTypes();
            if (pTypes.length == paramClasses.length) {
                boolean goodMethod = true;
                int i = 0;
                for (Type pType : pTypes) {
                    if (!ClassUtils.isAssignable(paramClasses[i++], (Class<?>) pType)) {
                        goodMethod = false;
                        break;
                    }
                }
                if (goodMethod) {
                    method.setAccessible(true);
                    return (T) method.invoke(instance, params);
                }
            }
        }

        throw new MethodNotFoundException("There are no methods found with name " + methodName + " and params " +
            Arrays.toString(paramClasses));
    }

    throw new MethodNotFoundException("There are no methods found with name " + methodName);
}

메서드는 autoboxed 매개변수의 호환성을 확인하기 위해 Apache ClassUtils를 사용합니다.

하나의 변형은 매우 강력한 Joor 라이브러리를 사용하고 있습니다 https://github.com/jooq/joor

MyObject myObject = new MyObject()
on(myObject).get("privateField");  

최종 정적 상수와 같은 모든 필드를 수정하고 상속 히어로 히어 히에서 콘크리트 클래스를 지정하지 않고 YNE 보호 방법을 호출 할 수 있습니다.

<!-- https://mvnrepository.com/artifact/org.jooq/joor-java-8 -->
<dependency>
     <groupId>org.jooq</groupId>
     <artifactId>joor-java-8</artifactId>
     <version>0.9.7</version>
</dependency>

당신이 사용할 수있는 매니 폴드 @Jailbreak 직접, 유형-안전 자바 반사 :

@Jailbreak Foo foo = new Foo();
foo.callMe();

public class Foo {
    private void callMe();
}

@Jailbreak 잠금을 해제합니다 foo 모든 회원에 직접 액세스하기 위해 컴파일러의 로컬 변수 Foo의 계층.

마찬가지로 사용할 수 있습니다 탈옥 () 일회성 사용을위한 확장 방법 :

foo.jailbreak().callMe();

Through the jailbreak() 방법으로 모든 멤버에 액세스 할 수 있습니다 Foo의 계층.

두 경우 모두 컴파일러는 마치 공개 메소드처럼 유형의 해안을 호출하는 방법을 해결하지만 Manifold는 후드 아래에서 효율적인 반사 코드를 생성합니다.

또는 유형에 정적으로 알려지지 않은 경우 사용할 수 있습니다. 구조 타이핑 인터페이스를 정의하기 위해 유형은 구현을 선언하지 않고도 만족할 수 있습니다. 이 전략은 유형 안전성을 유지하고 반사 및 프록시 코드와 관련된 성능 및 신원 문제를 피합니다.

더 자세히 알아보십시오 다양성.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top