2010-02-09 11 views
5

एक छोटी स्क्रिप्टइंजिन विकसित करने के हिस्से के रूप में, मैं प्रतिबिंबित रूप से जावा विधियों को कॉल करता हूं। स्क्रिप्ट इंजन द्वारा एक कॉल मुझे ऑब्जेक्ट विधि विधि और तर्कों की एक सरणी देता है। विधि को कॉल करने के लिए मैंने इसे Class.getMethod (नाम, तर्क प्रकार) पर कॉल के साथ हल करने का प्रयास किया।
हालांकि यह केवल तब काम करता है जब तर्क के वर्ग और विधि द्वारा अपेक्षित कक्षाएं समान होती हैं।कॉलिंग निकटतम फिटिंग विधि

Object o1 = new Object(); 
Object out = System.out; 
//Works as System.out.println(Object) is defined 
Method ms = out.getClass().getMethod("println",o1.getClass()); 
Object o2 = new Integer(4); 
//Does not work as System.out.println(Integer) is not defined 
Method mo = out.getClass().getMethod("println",o2.getClass()); 

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

निकटतम फिट होगा:

Object o1 = new Integer(1); 
Object o2 = new String(""); 
getMethod(name, o1.getClass())//println(Object) 
getMethod(name, o2.getClass())//println(String) 

अद्यतन:
स्पष्ट करने के लिए मैं क्या जरूरत है: स्क्रिप्ट इंजन एक छोटी परियोजना मैं अपने खाली समय में लिखना इसलिए कोई strikt नियम मेरे पास हो रहा है पीछा करना। तो मैंने सोचा कि इंजन से बुलाए गए तरीकों का चयन उसी प्रकार जावा कंपाइलर केवल गतिशील प्रकार के साथ संकलन समय पर विधियों का चयन करता है और ऑब्जेक्ट का स्थैतिक प्रकार काम नहीं करेगा। (ऑटोबॉक्सिंग के साथ या बिना)
यही वह है जो मैं पहले उम्मीद है कि Class.getMethod() हल होगा। लेकिन Class.getMethod() को समान वर्गों के रूप में तर्क प्रकार के रूप में आवश्यक है, जैसा कि सबक्लास का उपयोग करते हुए विधि घोषित करता है, परिणामस्वरूप कोई ऐसी विधि अपवाद नहीं होगी। यह अच्छे कारणों से हो सकता है, लेकिन मेरे लिए विधि बेकार बनाता है, क्योंकि मुझे पहले से पता नहीं है कि तर्क प्रकार फिट होंगे।
क्लास.getMethods() को कॉल करने के लिए एक वैकल्पिक होगा और लौटाए गए सरणी के माध्यम से पुनरावृत्त होगा और एक फिटिंग विधि खोजने का प्रयास करें। अगर मैं नहीं है सिर्फ पहला "अच्छा" विधि है जो मैं के पार चलो ले जाना चाहते हैं हालांकि यह जटिल हो जाएगा, तो मैं आशा व्यक्त की कि वहाँ एक मौजूदा समाधान होगा जो कम से कम हैंडल पर:

  • निकटतम फिट: अगर System.out.printf (स्ट्रिंग, स्ट्रिंग ...)
: arg.getClass() == उपवर्ग और तरीकों मीटर (सुपर क्लास), मीटर (उपवर्ग) तो मीटर (उपवर्ग)
  • चर तर्क फोन

    ऑटोबॉक्सिंग के लिए समर्थन भी अच्छा होगा।
    यदि कोई कॉल हल नहीं किया जा सकता है तो यह एक अपवाद फेंक सकता है (एम (स्ट्रिंग, ऑब्जेक्ट), एम (ऑब्जेक्ट, स्ट्रिंग), args = स्ट्रिंग, स्ट्रिंग)
    (यदि आपने इसे यहां तक ​​बनाया है, तो समय लेने के लिए धन्यवाद इसे पढ़ें :-))

  • +0

    पहले "निकटतम" के लिए कड़े नियमों को परिभाषित है, तो कार्यान्वयन एक विस्तार है। – Bozho

    +0

    बस मैं क्या सोच रहा था। लेकिन सभी पैडेंटिकली-सही उत्तरदाताओं के लिए, "निकटतम परिभाषित करें" के लिए, मुझे एक आसान मिला है: वह जिसे जावा सामान्य रूप से चुनता है (मुझे क्लास लोड पर लगता है)। –

    उत्तर

    2

    जैसा कि अन्य ने इंगित किया है कि ऐसा कोई मानक तरीका नहीं है जो आपको करता है, इसलिए आपको अपना खुद का अधिभार समाधान एल्गोरिदम लागू करना होगा।

    यह शायद मतलब होगा javac के अधिभार संकल्प नियमों से यथासंभव पालन करने के लिए:
    http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#292575
    आप शायद एक गतिशील टाइप पटकथा भाषा के लिए जेनरिक अनदेखा कर सकते हैं, लेकिन यह है कि संकलक उत्पन्न करता है आप अभी भी bridge methods से लाभ हो सकता खुद ब खुद।

    कुछ नुकसान के लिए बाहर देखने के लिए:

    • Class.isAssignableFrom, स्वत: चौड़ा आदिम रूपांतरण के बारे में पता नहीं है, क्योंकि इन वाक्यात्मक संकलक में लागू चीनी कर रहे हैं; वे वीएम या कक्षा पदानुक्रम में नहीं होते हैं। जैसे int.class.isAssignableFrom(short.class)false देता है।
    • इसी प्रकार Class.isAssignableFrom ऑटो-मुक्केबाजी के बारे में नहीं जानता है। Integer.class.isAssignableFrom(int.class)false देता है।
    • Class.isInstance और Class.cast एक तर्क के रूप में Object ले लो; आप उन्हें आदिम मूल्यों को पारित नहीं कर सकते हैं। उन्होंने यह भी एक Object लौटने के लिए, ताकि वे unboxing के लिए इस्तेमाल नहीं किया जा सकता है ((int) new Integer(42) जावा स्रोत में कानूनी है लेकिन int.class.cast(new Integer(42)) एक अपवाद फेंकता है।)
    1

    AFAIK, इस तरह की चीज करने का कोई आसान तरीका नहीं है। निश्चित रूप से, ऐसा करने के लिए मानक जावा क्लास पुस्तकालयों में कुछ भी नहीं है।

    समस्या यह है कि कोई भी "सही" उत्तर नहीं है। आपको अपने सभी उपयोग-मामलों पर विचार करने की आवश्यकता है, तय करें कि "सही विधि" क्या होनी चाहिए और तदनुसार अपने प्रतिबिंब कोड को लागू करना चाहिए।

    2

    मैं सुझाव दूंगा कि आप getMethods() का उपयोग करें। यह सभी सार्वजनिक तरीकों की एक सरणी देता है (Method[])।

    सबसे महत्वपूर्ण यहाँ बात है: वर्ग एक ही पैरामीटर प्रकार के साथ कई सार्वजनिक सदस्य तरीकों वाणी
    " , तो वे सभी वापस आ सरणी में शामिल किए गए हैं। "

    आप तो करने की आवश्यकता होगी क्या को यह सरणी में परिणाम उपयोग करने के लिए जो उनमें से एक का निर्धारण (यदि हो तो) निकटतम मिलान कर रहे हैं। चूंकि निकटतम मिलान आपकी आवश्यकताओं और विशिष्ट एप्लिकेशन पर बहुत अधिक निर्भर करता है, इसलिए इसे स्वयं कोड करने के लिए यह समझ में आता है।


    नमूना कोड कैसे आप ऐसा करने के बारे में जा सकते हैं में से एक दृष्टिकोण को दर्शाता हुआ: इस उदाहरण में

    public Method getMethod(String methodName, Class<?> clasz) 
    { 
        try 
        { 
         Method[] methods = clasz.getMethods(); 
         for (Method method : methods) 
         { 
          if (methodName.equals(method.getName())) 
          { 
           Class<?>[] params = method.getParameterTypes(); 
           if (params.length == 1) 
           { 
            Class<?> param = params[0]; 
            if ((param == int.class) || (param == float.class) || (param == float.class)) 
            { 
             //method.invoke(object, value); 
             return method; 
            } 
            else if (param.isAssignableFrom(Number.class)) 
            { 
             return method; 
            } 
            //else if (...) 
            //{ 
            // ... 
            //} 
           } 
          } 
         } 
        } 
        catch (Exception e) 
        { 
         //some handling 
        } 
        return null; 
    } 
    

    , getMethod(String, Class<?>) विधि एक विधि वापस आ जाएगी कि केवल एक पैरामीटर है जो एक int है, float साथ , double, या Number का एक सुपरक्लास।

    यह एक प्राथमिक कार्यान्वयन है - यह बिल को फिट करने वाली पहली विधि देता है। आपको मिलान करने वाली सभी विधियों की एक सूची बनाने के लिए इसे विस्तारित करने की आवश्यकता होगी, और फिर उन्हें किसी प्रकार के मानदंडों के अनुसार क्रमबद्ध करें, और सर्वोत्तम मिलान विधि वापस करें।

    फिर आप इसे आगे भी अधिक सामान्य getMethod(String, Class<?>) विधि बनाने, संभव "बंद मैच" परिदृश्यों के अधिक संभाल करने से ले जा सकते हैं, और संभवतः एक से भी अधिक पैरामीटर

    HTH


    संपादित करें: जैसा कि @ फिन्नव ने इंगित किया है, Class#isAssignableFrom(Class<?> cls) का उपयोग करते समय सावधान रहें, क्योंकि मेरे नमूने कोड में, Number ऑब्जेक्ट्स से अलग से प्राइमेटिव का परीक्षण करना।

    +1

    @bguiz, अच्छा समाधान। बस यह जोड़ना चाहते हैं कि आप 'class.isPrimitive() 'और' Class.isArray() 'के लिए परीक्षण कर सकते हैं IAignignFrom() की कुछ सीमाओं के आसपास काम करने के लिए। @ finnw का जवाब भी। – bojangle