2014-10-02 11 views
5

अगर मैं, उदाहरण के लिए, एक विधि कक्षा प्रकार के लिए varargs का उपयोग करता है कि इस तरह एक सुपर वर्ग फैली है:varargs

public static <E extends Example> void test(Class<E>... es){} 

तो मैं दो अलग-अलग के साथ कि विधि कॉल करने की कोशिश उदाहरण के उप-वर्ग, मैं केवल ऐसा कर सकता हूं यदि मैं इसमें दो वर्गों के साथ एक सरणी बना देता हूं।

//this does not work 
test(E1.class,E2.class); 
//this does work 
test(new Class[]{E1.class,E2.class}); 
public class E1 extends Example {} 
public class E2 extends Example {} 

यह क्यों है?

उत्तर

6

इस लाइन संकलित करता है नहीं:

test(E1.class,E2.class); 

केवल एक ही प्रकार पैरामीटर E है, और जावा तर्कों की अनुमानित प्रकार हूबहू मिलना चाहिए। यह Example का अनुमान नहीं लगा सकता है, क्योंकि ऑब्जेक्ट Class<E1> और Class<E2> हैं, Class<Example> नहीं। जावा जेनेरिक का आविष्कार इसे होने से रोकता है।

आप test के सामान्य प्रकार पैरामीटर पर एक ऊपरी बाध्य वाइल्डकार्ड शुरू करने से इस पर काम कर सकते हैं:

public static <E extends Example> void test(Class<? extends E>... es) 

यह, जावा E के लिए Example अनुमान लगाने के लिए अनुमति देता है E1 और E2 साथ ऊपरी बाध्य वाइल्डकार्ड संतोषजनक।

दूसरी पंक्ति जेनिक्स को छोड़कर और "अनचेक कॉल" चेतावनी उत्पन्न करने, Class es की कच्ची सरणी बनाती है।

new Class[]{E1.class,E2.class} 

आप यहाँ Class करने के लिए एक प्रकार का तर्क प्रदान करने के लिए प्रयास करने के लिए थे, तो आप किसी भी आधे रास्ते उचित प्रकार पैरामीटर के साथ एक संकलक त्रुटि मिलती हैं:

// Needs Class<Example> but found Class<E1> and Class<E2> 
test(new Class<Example>[]{E1.class,E2.class}); 

// Needs Class<E1> but found Class<E2> 
test(new Class<E1>[]{E1.class,E2.class}); 

// Needs Class<E2> but found Class<E1> 
test(new Class<E2>[]{E1.class,E2.class}); 

एक वाइल्डकार्ड का उपयोग करके अनुमान संतोषजनक यहां वास्तविक समस्या को हल करता है - जेनेरिक सरणी निर्माण।

// Generic array creation 
test(new Class<? extends Example>[]{E1.class,E2.class}); 
+0

घोषित करने की कोई स्पष्ट आवश्यकता नहीं थी। यह मेरे कार्यक्रम के लिए कभी भी हानिकारक नहीं था, लेकिन मैं निश्चित रूप से थोड़ी देर के लिए अपने सिर खरोंच कर रहा हूँ। मैं वास्तव में स्पष्टीकरण की सराहना करता हूं। – Squirvin

2

आप उदाहरण को विस्तारित करने वाले एक वर्ग के जेनेरिक ई को परिभाषित करते हैं। आप अपने कॉल में दो अलग-अलग वर्गों का संदर्भ नहीं दे सकते क्योंकि यह नहीं पता कि ई किस प्रकार का है। यह केवल एक प्रकार की अपेक्षा करता है।

इस हालांकि काम नहीं करता:

test(E1.class, E2.class); 

यह करता है:

test(E1.class, E1.class); 

कारण आप एक सरणी के साथ यह कर सकते हैं प्रकार विलोपन के कारण है। कंपाइलर नहीं देखता है कि सरणी के भीतर कक्षाएं अलग हैं।

यदि आप Example तक फैले किसी भी वर्ग को स्वीकार करने के लिए अपनी विधि बदलते हैं तो यह काम करेगा।

public static void test(Class<? extends Example>...classes) 
+1

मुझे लगता है कि आपने इसे बहुत अच्छी तरह से समझाया है। लेकिन ओपी के उदाहरण के बराबर होने के लिए, आपका हस्ताक्षर 'सार्वजनिक स्थिर होना चाहिए <ई उदाहरण> शून्य परीक्षण (कक्षा ... कक्षाएं) बढ़ाता है। यह (किसी भी मामले में) एक '-क्लिंट: अनचेक' चेतावनी देगा, यद्यपि। – 5gon12eder

+0

@ 5gon12eder: आपके द्वारा दिए गए हस्ताक्षर और इस उत्तर में से एक बिल्कुल समकक्ष है, यानी वे तर्कों की सटीक कक्षा को स्वीकार करते हैं। सरल (जिसे इस उत्तर में दिया गया है) हमेशा पसंद किया जाना चाहिए क्योंकि प्रकार पैरामीटर अनावश्यक है। – newacct

+0

@ न्यूवेक्ट वे तर्क के समान वर्ग को स्वीकार करते हैं, लेकिन यदि आप सामान्य प्रकार का संदर्भ लेना चाहते हैं, तो आपको अधिक वर्बोज़ सिंटैक्स की आवश्यकता होगी। चूंकि ओपी में, 'टेस्ट' रिटर्न 'शून्य' है और इसमें एक खाली निकाय है, आप तर्क दे सकते हैं कि हम किसी भी प्रकार का संदर्भ नहीं लेना चाहते हैं, लेकिन आम तौर पर बोलते हुए, वर्बोज सिंटैक्स भी अधिक शक्तिशाली होता है। – 5gon12eder

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