किसी भी तरह से एक निजी विधि लागू करने के लिए?


146

मेरे पास एक वर्ग है जो 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, तो यह a के साथ विफल हो जाती है NoSuchMethodException। मैं इसे विधि publicबनाकर या इसे प्राप्त करने के लिए एक और वर्ग बनाकर हल कर सकता था ।

लंबी कहानी छोटी, मैं बस सोच रहा था कि क्या privateप्रतिबिंब के माध्यम से एक विधि तक पहुंचने का एक तरीका था।

जवाबों:


303

आप प्रतिबिंब के साथ निजी विधि को लागू कर सकते हैं। पोस्ट किए गए कोड के अंतिम बिट को संशोधित करना:

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

कुछ युगल हैं। सबसे पहले, getDeclaredMethodकेवल वर्तमान में घोषित विधि ही Classखोजेगी, न कि सुपरपोर्ट्स से विरासत में मिली। इसलिए, यदि आवश्यक हो तो कंक्रीट वर्ग पदानुक्रम को पार करें। दूसरा, एक विधि के SecurityManagerउपयोग को रोक सकता है setAccessible। तो, इसे PrivilegedAction(उपयोग AccessControllerया Subject) के रूप में चलाने की आवश्यकता हो सकती है ।


2
जब मैंने अतीत में ऐसा किया है, तो मैंने विधि को कॉल करने के बाद मेथडेसिटिव (झूठी) भी कहा है, लेकिन मुझे पता नहीं है कि यह आवश्यक है या नहीं।
शीस्टमीयर

16
नहीं, जब आप पहुंच-योग्यता सेट करते हैं, तो यह केवल उस उदाहरण पर लागू होता है। जब तक आप उस विशेष विधि ऑब्जेक्ट को अपने नियंत्रण से भागने नहीं देते, यह सुरक्षित है।
एरिकसन

6
तो फिर निजी तरीकों का क्या मतलब है अगर उन्हें कक्षा से बाहर से बुलाया जा सकता है?
पीटर Ajtai

2
यह भी सुनिश्चित करें कि आप getDeclaredMethod()बस के बजाय कॉल करते हैं getMethod()- यह निजी तरीकों के लिए काम नहीं करेगा।
एरकेन

1
@PeterAjtai देर से प्रतिक्रिया के लिए क्षमा करें, लेकिन इसे इस तरह से सोचें: आजकल ज्यादातर लोग अपने दरवाजे बंद कर लेते हैं, भले ही उन्हें पता हो कि ताला तुच्छ रूप से टूट सकता है या पूरी तरह से चक्कर लगाया जा सकता है। क्यों? क्योंकि यह ज्यादातर ईमानदार लोगों को ईमानदार रखने में मदद करता है। आप privateएक समान भूमिका निभाते हुए पहुंच के बारे में सोच सकते हैं ।
एरिक्सन

34

getDeclaredMethod()एक निजी विधि ऑब्जेक्ट प्राप्त करने के लिए उपयोग करें और फिर method.setAccessible()वास्तव में इसे कॉल करने की अनुमति देने के लिए उपयोग करें।


अपने स्वयं के उदाहरण में ( stackoverflow.com/a/15612040/257233 ) मुझे java.lang.StackOverflowErrorकॉल न करने पर मिलता है setAccessible(true)
रॉबर्ट मार्क ब्रैम

25

यदि विधि गैर-आदिम डेटा प्रकार को स्वीकार करती है, तो निम्न विधि का उपयोग किसी भी वर्ग की निजी पद्धति को लागू करने के लिए किया जा सकता है:

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

7
पैरामाउंट की आवश्यकता क्यों है ? क्या आप सिर्फ params.length का उपयोग नहीं कर सकते हैं ?
साद मलिक

7

आप इसे वसंत के ReflectionTestUtils ( org.springframework.test.util.ReflectionTestUtils ) का उपयोग करके कर सकते हैं

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

उदाहरण: यदि आपके पास एक निजी विधि के साथ एक वर्ग है square(int x)

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

कोर स्प्रिंग में एक अधिक सीमित परावर्तन यूटिल्स भी है ।
थंडरफोर्ज

3

मुझे प्रतिबिंब के माध्यम से निष्पादन संरक्षित विधियों के लिए पूर्ण कोड प्रदान करें। यह जेनेरिक, ऑटोबॉक्सड परम और शून्य मान सहित किसी भी प्रकार के परिमों का समर्थन करता है

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

ऑटोबॉक्स्ड पैरामस की अनुकूलता की जाँच के लिए विधि अपाचे क्लासयूटिल्स का उपयोग करती है


900 से अधिक विचारों और स्वीकृत उत्तर के साथ 9 साल पुराने प्रश्न का उत्तर देने का कोई मतलब नहीं है। इसके बजाय अनुत्तरित प्रश्नों का उत्तर दें।
अनुराग बैश्य

0

एक और संस्करण बहुत शक्तिशाली JOOR लाइब्रेरी https://github.com/jOOQ/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>

0

आप प्रत्यक्ष, प्रकार-सुरक्षित जावा प्रतिबिंब के लिए मैनिफोल्ड के @ जर्कब्रेक का उपयोग कर सकते हैं :

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

public class Foo {
    private void callMe();
}

@Jailbreakfooसंकलक के Fooपदानुक्रम में सभी सदस्यों तक सीधी पहुँच के लिए स्थानीय चर को अनलॉक करता है ।

इसी तरह आप एकबारगी उपयोग के लिए जेलब्रेक () एक्सटेंशन विधि का उपयोग कर सकते हैं:

foo.jailbreak().callMe();

jailbreak()विधि के माध्यम से आप किसी भी सदस्य के Fooपदानुक्रम में पहुँच सकते हैं।

दोनों ही मामलों में कंपाइलर आपके लिए टाइप-सेफ तरीके से कॉल कॉल को हल करता है, जैसे कि कोई सार्वजनिक तरीका, जबकि मैनिफोल्ड हुड के तहत आपके लिए कुशल प्रतिबिंब कोड उत्पन्न करता है।

वैकल्पिक रूप से, यदि प्रकार को सांख्यिकीय रूप से नहीं जाना जाता है, तो आप एक इंटरफ़ेस को परिभाषित करने के लिए संरचनात्मक टंकण का उपयोग कर सकते हैं एक प्रकार किसी भी कार्यान्वयन को घोषित किए बिना संतुष्ट कर सकता है। यह रणनीति प्रकार-सुरक्षा को बनाए रखती है और प्रतिबिंब और प्रॉक्सी कोड से जुड़े प्रदर्शन और पहचान के मुद्दों से बचती है।

कई गुना के बारे में पता चलता है ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.