سؤال

لدي الدرجة التي تستخدم XML و التفكير في العودة Objects إلى فئة أخرى.

عادة هذه الكائنات الفرعية حقول كائن خارجي, ولكن في بعض الأحيان أنه شيء أريد أن تولد على الطاير.لقد حاولت شيئا من هذا القبيل ولكن دون جدوى.أعتقد أن هذا بسبب جافا لن تسمح لك بالوصول إلى 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 الحالية، وليس رثت من supertypes. لذا، اجتياز أعلى التسلسل الهرمي الطبقة الخرسانية إذا لزم الأمر. ثانيا، يمكن للSecurityManager منع استخدام أسلوب 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;
    }

ومعلمة المقبولة هي الكائنات، 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");

ويمكنك القيام بذلك باستخدام ReflectionTestUtils الربيع (<لأ href = "https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/util/ReflectionTestUtils.html "يختلط =" noreferrer نوفولو "> org.springframework.test.util.ReflectionTestUtils )

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

وعلى سبيل المثال: إذا كان لديك فئة مع square(int x) طريقة خاصة

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

واسمحوا لي أن توفير رمز كاملة لطرق حماية التنفيذ عن طريق التفكير. وهو يدعم أي نوع من أنواع بارامس بما في ذلك الأدوية، بارامس autoboxed والقيم الخالية

@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);
}
يستخدم

والطريقة ClassUtils اباتشي لفحص توافق بارامس autoboxed

واحد أكثر البديل هو استخدام قوية جدا JOOR مكتبة https://github.com/jOOQ/jOOR

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

وأنها تسمح لتعديل أي مجالات مثل الثوابت ثابتة النهائية، وندعو وسائل حماية yne دون تحديد فئة محددة في hierarhy الميراث

<!-- 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>

يمكنك استخدام المنوع @الهروب من السجن مباشرة, نوع-آمنة التفكير Java:

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

public class Foo {
    private void callMe();
}

@Jailbreak يفتح foo المتغير المحلي في المجمع من أجل الوصول المباشر إلى جميع الأعضاء في Foo's الهرمي.

كما يمكنك استخدام الهروب من السجن() طريقة التمديد لمرة واحدة استخدام:

foo.jailbreak().callMe();

من خلال jailbreak() الطريقة يمكنك الوصول إلى أي عضو في Foo's الهرمي.

في كلتا الحالتين مترجم يحل طريقة اتصال لك نوع بأمان ، كما لو كان أسلوب عام ، في حين المنوع يولد كفاءة انعكاس رمز لك تحت غطاء محرك السيارة.

بدلا من ذلك, إذا كان نوع غير معروف بشكل ثابت ، يمكنك استخدام هيكلية الكتابة تحديد واجهة نوع يمكن أن يرضي دون أن تعلن تنفيذها.هذه الاستراتيجية يحافظ على نوع-السلامة والابتعاد عن الأداء وقضايا الهوية المرتبطة انعكاس وكيل رمز.

اكتشف المزيد حول المنوع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top