जावा जेनेरिक वाइल्डकार्डिंग कई वर्गों के साथ


385

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

मैं कर सकता हूँ:

Class<? extends ClassA>

या:

Class<? extends InterfaceB>

लेकिन मैं दोनों नहीं कर सकता। क्या इसे करने का कोई तरीका है?

जवाबों:


613

दरअसल, आप वही कर सकते हैं जो आप चाहते हैं। यदि आप कई इंटरफेस या एक क्लास प्लस इंटरफेस प्रदान करना चाहते हैं, तो आपको अपने वाइल्डकार्ड को कुछ इस तरह देखना होगा:

<T extends ClassA & InterfaceB>

पेज के नीचे , विशेष रूप से बंधे हुए टाइप पैरामीटर्स सेक्शन में जेनरिक ट्यूटोरियल देखें । यदि आप चाहें, तो आप वास्तव में एक से अधिक इंटरफ़ेस की सूची बना सकते हैं ।& InterfaceName

यह मनमाने ढंग से जटिल हो सकता है। प्रदर्शित करने के लिए, JavaDoc घोषणा देखें Collections#max, जो (दो लाइनों पर लिपटी) है:

public static <T extends Object & Comparable<? super T>> T
                                           max(Collection<? extends T> coll)

इतना जटिल क्यों? जैसा कि जावा जेनेरिक एफएक्यू में कहा गया है: द्विआधारी संगतता को संरक्षित करने के लिए

ऐसा लगता है कि यह चर घोषणा के लिए काम नहीं करता है, लेकिन यह एक वर्ग पर एक सामान्य सीमा डालते समय काम करता है। इस प्रकार, आप जो चाहते हैं उसे करने के लिए, आपको कुछ हुप्स के माध्यम से कूदना पड़ सकता है। लेकिन आप यह कर सकते हैं। आप कुछ ऐसा कर सकते हैं, अपनी कक्षा में एक सामान्य सीमा डालें और फिर:

class classB { }
interface interfaceC { }

public class MyClass<T extends classB & interfaceC> {
    Class<T> variable;
}

पाने के लिए variableकि आप चाहते हैं प्रतिबंध है। अधिक जानकारी और उदाहरणों के लिए, जावा 5.0 में जेनरिक के पेज 3 को देखें । ध्यान दें, में <T extends B & C>, कक्षा का नाम पहले आना चाहिए, और इंटरफेस का पालन करना चाहिए। और निश्चित रूप से आप केवल एक ही वर्ग को सूचीबद्ध कर सकते हैं।


94
यह मददगार है। यह ध्यान देने योग्य है कि कक्षा को पहले आना चाहिए , आप यह नहीं कह सकते कि '<T इंटरफ़ेसब और क्लास ए> का विस्तार करता है।'
एरिकएस

5
टी के लिए आप ऐसा कैसे करते हैं या तो एक वर्ग का विस्तार करना चाहिए या एक इंटरफ़ेस लागू करना चाहिए?
रघुनाथ जवाहर

1
@ रघुनाथजवाहर: आप इस बारे में बहुत खुलकर बात नहीं कर सकते। आपके पास कुछ सीमाएँ हैं, और उनमें से एक अग्रिम में पता चल रहा है कि आपके पास कहाँ इंटरफेस होगा और आपके पास कहाँ कक्षाएं होंगी, और आप विरासत का उपयोग कैसे करेंगे। यदि आप एक वर्ग या एक इंटरफ़ेस होगा तो आपको एक प्रकार के पैरामीटर के लिए बहुत कुछ जानना होगा।
एडी

4
आपके उत्तर की पहली पंक्ति "आपके वाइल्डकार्ड को कुछ इस तरह दिखती है"। ?उस अभिव्यक्ति में कोई भी नहीं है, तो क्या यह वास्तव में एक "वाइल्डकार्ड" है? मैं पूछता हूं क्योंकि मैं पूरी तरह से "दो चीजों को एक बार में" अवधारणा पर काम नहीं कर सकता जब प्रकार पैरामीटर वास्तव में एक वाइल्डकार्ड है।
The111

1
हाँ, यह वास्तव में वाइल्डकार्ड नहीं है और आप वह नहीं कर सकते जो ओपी ने वाइल्डकार्ड के साथ किया था। आप वह कर सकते हैं जो ओपी चाहता था, प्रभावी रूप से, सिर्फ एक वाइल्डकार्ड के साथ नहीं।
एडी

17

आप इसे "अनाम" प्रकार के मापदंडों (यानी, वाइल्डकार्ड जो उपयोग करते हैं ?) के साथ नहीं कर सकते हैं, लेकिन आप इसे "नामित" प्रकार के मापदंडों के साथ कर सकते हैं। बस विधि या वर्ग स्तर पर टाइप पैरामीटर घोषित करें।

import java.util.List;
interface A{}
interface B{}
public class Test<E extends B & A, T extends List<E>> {
    T t;
}

2
वाइल्डकार्ड की अनुमति क्यों नहीं है? यानी मैं यह नहीं देखता कि यह मान्य क्यों नहीं होना चाहिए: ArrayList <? ClassA & InterfaceB> सूची का विस्तार करता है; और फिर यदि आपने सूची में से एक तत्व निकाला है, तो आप उसे ClassA के प्रकार या InterfaceB के प्रकार के साथ असाइन कर सकते हैं
Mark

एक चर के साथ वाइल्डकार्ड की जगह एक महान तकनीक है! लेकिन यह हमेशा काम नहीं करता है। उदाहरण के लिए, जावा एनोटेशन मान प्रकारों में नाम प्रकार चर की अनुमति नहीं देता है, जबकि यह वाइल्डकार्ड की अनुमति देता है।
जुग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.