2015-10-05 8 views
36

की एक विधि लागू मैं दूसरे दिन है कि आप इसएक अनाम वर्ग

new Object() { 
    void hello() { 
     System.out.println("Hello World!"); 
    } 
}.hello(); 

यह मेरे लिए वास्तव में अजीब लगता है क्या कर सकते हैं सीखा है। निश्चित रूप से बनाए गए ऑब्जेक्ट का स्थिर प्रकार Object है, इसलिए hello() कोई विधि नहीं है? क्या यह लगभग पूरी तरह से व्यर्थ नहीं है (उदाहरण के लिए hello दो बार आमंत्रित करना संभव नहीं है)।

मेरे पास इसके बारे में 2 प्रश्न हैं।

  1. क्या कोई मुझे उस विनिर्देश के हिस्से में इंगित कर सकता है जो इसे संबोधित करता है?
  2. क्या मैं सोच रहा हूं कि hello का आह्वान करने का एकमात्र तरीका तुरंत इस तरह है। प्रतिबिंब के बारे में क्या?

धन्यवाद

+0

[JLS-15.9.5 उम्मीद नहीं थी बना सकते हैं। बेनामी कक्षा घोषणाएं] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.9.5) –

+0

आपको प्रतिबिंब के माध्यम से इसे प्राप्त करने में सक्षम होना चाहिए। लेकिन हाँ, यह लगभग पूरी तरह से व्यर्थ है।यदि आप विधियों को कॉल करना चाहते हैं, तो आप आमतौर पर अपनी अनाम कक्षा में एक इंटरफेस लागू करते हैं। – Thilo

+4

ठीक है, यदि आप एक अधिक विशिष्ट प्रकार (जैसे, * इंटरफ़ेस * का अज्ञात कार्यान्वयन) का अज्ञात वर्ग बनाते हैं, तो आप एक चर में संदर्भ को पकड़ सकते हैं जो आपको इच्छानुसार उन विधियों को कॉल करने देगा। –

उत्तर

16

क्या कोई मुझे उस विनिर्देश के हिस्से में इंगित कर सकता है जो इसे संबोधित करता है?

यह ज्यादातर खंड के विषय में Method invocation expressions में परिभाषित किया जाएगा: विधि का नाम बाहर

आंकड़ा करने के लिए

संकलन समय पर विधि मंगलाचरण के प्रसंस्करण में पहला कदम है लागू और जो वर्ग जा करने के लिए या उस नाम के तरीकों की परिभाषाओं की खोज के लिए इंटरफ़ेस।

  • [...]
  • हैं:

    वर्ग या खोज करने के लिए इंटरफेस के लिए, वहाँ छह मामलों पर विचार करने, रूप है कि MethodInvocation के बाईं कोष्ठक के पहले आता है पर निर्भर करता है फॉर्म Primary . [TypeArguments] Identifier है, तो T प्राथमिक अभिव्यक्ति के प्रकार होने दें। खोजने के लिए कक्षा या इंटरफ़ेस T है यदि T एक वर्ग या इंटरफ़ेस प्रकार है, या T की ऊपरी सीमा T एक प्रकार चर है।

यहाँ, प्राथमिक अभिव्यक्तिclass instance creation expression है। तो खोजने के लिए प्रकार अनाम प्रकार है।

क्या मैं सोच रहा हूं कि हैलो का आह्वान करने का एकमात्र तरीका तुरंत इस तरह है। प्रतिबिंब के बारे में क्या?

जब तक एक अभिव्यक्ति, अनाम प्रकार T का मूल्यांकन के रूप में है कि क्या सीधी पहुँच के माध्यम से है, या जेनरिक के माध्यम से, आप सदस्यों के लिए उपयोग (नियमित पहुँच नियम लागू होते हैं) है T घोषणा करता है कि तरह। यह विधियों तक ही सीमित नहीं है। आप फ़ील्ड या प्रकारों तक पहुंच सकते हैं, हालांकि यह प्रकार के लिए उपयोगी नहीं है। उदाहरण के लिए,

Object var = new Object() { 
    class Nested { 
    } 
}.new Nested(); 

कोई रास्ता नहीं संलग्न प्रकार बिना नेस्टेड प्रकार का उल्लेख करने के लिए के बाद से, आपको लगता है कि नेस्टेड प्रकार का एक चर की घोषणा नहीं कर सकते हैं। उपयोगिता बहुत जल्दी गिरती है। (संभवतः, यही कारण है कि आप इस अज्ञात वर्ग के भीतर static नेस्टेड प्रकार नहीं प्राप्त कर सकते हैं।)

प्रतिबिंब भी इस विधि को उजागर करता है। जेनरेट की गई अज्ञात कक्षा में यह विधि है, इसलिए आप इसे पुनर्प्राप्त कर सकते हैं और इसे आमंत्रित कर सकते हैं। प्रक्रिया एक ही है। तथ्य यह है कि उदाहरण अज्ञात वर्ग से है, इससे कोई फर्क नहीं पड़ता। How do I invoke a Java method when given the method name as a string? में प्रस्तुत की गई वही रणनीति लागू होती है।

उदाहरण के लिए,

Object ref = new Object() { 
    public void method() { 
     System.out.println("hidden"); 
    } 
}; 
Class<?> anonymousClass = ref.getClass(); 
Method method = anonymousClass.getMethod("method"); 
method.invoke(ref, new Object[0]); 

कभी इस तरह कोड लिखने है।

+2

@ElliottFrisch यह मामला नहीं होना चाहिए। 'नया ऑब्जेक्ट() {} .getClass() 'रिटर्न' क्लास com.example.Example $ 1' मेरे लिए। –

+0

ओरेकल जावा 8, लिनक्स। 'o.getClass()। getMethods() 'ने' हैलो 'विधि नहीं दी है। यही वह जगह है जहां मैंने रोका। –

+4

@ सेलियट यदि आप उनका कोड इस्तेमाल करते हैं, तो यह काम नहीं करेगा क्योंकि विधि सार्वजनिक नहीं है। –

12

के रूप में तैनात, वहाँ एक रास्ता Object उदाहरण से अनाम तरीकों पाने के लिए नहीं है। और, यह Anonymous classes व्यर्थ बिंदु बनाता है। लेकिन, आप इंटरफ़ेस को लागू करने के लिए इसका उपयोग कर सकते हैं (और मैं आमतौर पर)। कुछ की तरह,

static interface Hello { 
    void hello(); 
} 
public static void main(String[] args) { 
    Hello o = new Hello() { 
     public void hello() { 
      System.out.println("Hello World!"); 
     } 
    }; 
    o.hello(); 
} 

या, और अधिक सामान्यतः, JFC/घुमाओ और ActionListener साथ कॉल-बैक के लिए।

11

Sotirios' answer को जोड़ना है, तो यहां प्रतिबिंब के माध्यम से विधि आह्वान करने के लिए है:

Object o = new Object() { 
    void hello() { 
     System.out.println("Hello World!"); 
    } 
}; 

Method hello = o.getClass().getDeclaredMethod("hello"); 
hello.invoke(o); 

यह आपको एक बार से अधिक विधि कॉल करने के लिए अनुमति देता है, लेकिन उस के अलावा अन्य, थोड़ा समझ में आता है।

+0

धन्यवाद। मैं सहमत हूं कि एक पूर्ण उत्तर के लिए जरूरी है। –

9

बेनामी वर्ग आलसी प्रोग्रामर के लाभ के लिए है - बातें नामकरण बहुत कठिन है :)

बेनामी वर्ग बहुत ज्यादा एक स्थानीय वर्ग की तरह है। यदि एक स्थानीय वर्ग सिर्फ एक वस्तु बनाने के लिए है, जिसका उपयोग केवल सुपरटेप के रूप में किया जाता है, तो हम इसके बजाय एक अज्ञात वर्ग बना सकते हैं जो अधिक संक्षिप्त है।

बेनामी क्लास undenotable (प्रोग्रामर के लिए) है, जो ठीक है क्योंकि हमें इसे फिर से संदर्भित करने की आवश्यकता नहीं है। हालांकि, कंपाइलर के लिए, कक्षा का नाम बहुत अधिक है, और स्पष्ट रूप से नामित कक्षाओं से अलग तरीके से इसका इलाज करने का कोई कारण नहीं है। अभिव्यक्ति का स्थिर प्रकार ठोस उपclass है, और वस्तु के सदस्य उस वर्ग के सदस्य हैं। क्या यह सुविधा (hello() पर कॉल करने में सक्षम है) व्यर्थ? केवल तभी यदि आप स्थानीय वर्ग व्यर्थ मानते हैं (और वास्तव में स्थानीय वर्ग का शायद ही कभी उपयोग किया जाता है)। यहां एक example है जहां मैंने उस सुविधा का उपयोग किया (मज़ेदार के लिए)।

हालांकि प्रकार अनावश्यक है, प्रकार एपीआई के माध्यम से स्वयं के रूप में जीवित रह सकता है। उदाहरण के लिए,

Objects.requireNonNull(new Object(){ void hello(){} }).hello(); 

हालांकि हम प्रकार का नाम नहीं सकते हैं, यह है जहाँ यह निष्कर्ष निकाला जा सकता नामित किए जाने की जरूरत नहीं है।

Collections.singleton(new Object(){ void hello(){} }) 
     .forEach(o->{ o.hello(); o.hello(); }); 

और हम लोगों के लिए पहेलियों के जो स्थिर प्रकार

Collections.singleton(new Object(){}).add(new Object()); // does not compile! why? 
+1

तो मेरा आधार पूरी तरह से गलत है - आप प्रतिबिंब के बिना दो बार 'हैलो() 'कॉल कर सकते हैं। यह अच्छा है, लेकिन थोड़ा हास्यास्पद भी है। आपके उत्तर से प्रेरित, मैंने इसे 'Collections.nCopies (2, नया ऑब्जेक्ट() {...}) के साथ प्रबंधित किया। प्रत्येक (ओ -> ओ.हेल्लो()); ' –

+2

हाँ, आपका एक बेहतर प्रदर्शन है। – ZhongYu

+1

जबकि प्रोग्रामर अभिव्यक्ति के ठोस प्रकार का नाम नहीं दे सकता है, जावा भी ऐसे कई स्थानों को प्रदान करता है जहां आपको प्रकार का नाम देने की आवश्यकता नहीं है, उदा। लैम्ब्डा पैरामीटर। – ZhongYu

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