2009-05-19 18 views
107

मेरे पास एक कक्षा है जो 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 विधि तक पहुंचने का कोई तरीका था या नहीं।

उत्तर

233

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

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

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

+1

जब मैंने अतीत में ऐसा किया है, तो मैंने विधि को कॉल करने के बाद method.setAccessible (false) भी कहा है, लेकिन मुझे यह नहीं पता कि यह आवश्यक है या नहीं। – shsteimer

+12

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

+5

मैं बिल्कुल प्यार करता हूँ आप दोस्त साथी। बहुत बढ़िया उत्तर + खराब कोड == इतना बुरा दिन नहीं। – droope

32

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

+7

वास्तव में पूरा हो गया है लागू किया जा सकता है। –

+0

मेरे अपने उदाहरण में (http://stackoverflow.com/a/15612040/257233) मुझे 'java.lang.StackOverflowError' मिलता है अगर मैं' setAccessible (true) 'नहीं कहता हूं। –

21

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

public static Object genericInvokMethod(Object obj, String methodName, 
      int paramCount, Object... params) { 
     Method method; 
     Object requiredObj = null; 
     Object[] parameters = new Object[paramCount]; 
     Class<?>[] classArray = new Class<?>[paramCount]; 
     for (int i = 0; i < paramCount; i++) { 
      parameters[i] = params[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) genericInvokMethod(t, "concatString", 2, "Hello", "Mr.x"); 
+5

_paramCount_ क्यों आवश्यक है? क्या आप सिर्फ * params.length * का उपयोग नहीं कर सकते? –

संबंधित मुद्दे

 संबंधित मुद्दे