programing

개인 메서드를 호출할 방법이 있나요?

prostudy 2022. 7. 31. 21:05
반응형

개인 메서드를 호출할 방법이 있나요?

XML과 리플렉션을 사용하여 반환하는 클래스가 있습니다.Object다른 클래스로 이동합니다.

일반적으로 이러한 객체는 외부 객체의 하위 필드이지만, 경우에 따라서는 즉시 생성해야 할 수 있습니다.이런 걸 해봤는데 안 되더라고요.그건 자바가 당신이 접속하는 것을 허락하지 않기 때문인 것 같습니다.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, 슈퍼타입에서 상속되지 않습니다.따라서 필요에 따라 구체적인 클래스 계층을 따라 올라가십시오.둘째, aSecurityManager의 사용을 방지할 수 있습니다.setAccessible방법.즉, 이 경우, 이 기능을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);
}
}

메서드 concatString은 다음과 같이 호출할 수 있습니다.

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

Reflection을 사용하여 이 작업을 수행할 수 있습니다.스프링의 TestUtils(또는 스프링프레임워크.test.util).반사테스트 유틸리티)

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

메서드는 Apache ClassUtils를 사용하여 자동 상자화된 매개 변수의 호환성을 검사합니다.

또 하나의 변종에서는 매우 파워풀한 JOOR 라이브러리를 사용하고 있습니다.

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

상속 계층에서 구체적인 클래스를 지정하지 않고 최종 정적 상수 및 보호된 메서드와 같은 필드를 수정할 수 있습니다.

<!-- 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사용하여 직접적이고 안전한 Java 리플렉션을 수행할 수 있습니다.

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

public class Foo {
    private void callMe();
}

@Jailbreak잠금을 해제하다foo컴파일러의 로컬 변수에서 모든 멤버에 직접 액세스 할 수 있습니다.Foo의 계층입니다.

마찬가지로 jailbreak() 확장 메서드를 일회성으로 사용할 수 있습니다.

foo.jailbreak().callMe();

를 통해jailbreak()는 "내 멤버에 할 수 .Foo의 계층입니다.

두 경우 모두 컴파일러는 마치 공개 메서드처럼 사용자를 위한 메서드 호출을 안전하게 해결하는 반면, 매니폴드는 후드에서 사용자를 위한 효율적인 반사 코드를 생성합니다.

또는 유형이 정적으로 인식되지 않는 경우 Structural Typing을 사용하여 구현 선언 없이 유형이 충족할 수 있는 인터페이스를 정의할 수 있습니다.이 전략은 유형 안전을 유지하고 반사 및 프록시 코드와 관련된 성능 및 식별 문제를 방지합니다.

매니폴드에 대해 자세히 알아보십시오.

언급URL : https://stackoverflow.com/questions/880365/any-way-to-invoke-a-private-method

반응형