जावा जेनरिक - क्यों "विस्तारित टी" की अनुमति दी गई है लेकिन "टी को लागू नहीं"?


306

मुझे आश्चर्य होता है कि अगर वहाँ टाइप करने के लिए जावा के हमेशा " extends" के बजाय " implements" टाइप करने के लिए एक विशेष कारण है टाइपपैरमीटर की सीमाओं को परिभाषित करने के लिए।

उदाहरण:

public interface C {}
public class A<B implements C>{} 

निषिद्ध है लेकिन

public class A<B extends C>{} 

सही है। उसका क्या कारण है?


14
मुझे नहीं पता कि लोग क्यों सोचते हैं कि टेटसुजिन नो ओनी का जवाब वास्तव में सवाल का जवाब देता है। यह मूल रूप से शैक्षणिक शब्दों का उपयोग करते हुए ओपी की टिप्पणियों को दोहराता है, लेकिन कोई तर्क नहीं देता है। "क्यों कोई नहीं है implements?" - "क्योंकि वहाँ केवल है extends"।
थॉमस

1
थॉमसआर: ऐसा इसलिए है क्योंकि यह "अनुमत" का सवाल नहीं है, लेकिन इसका अर्थ है: इसमें कोई अंतर नहीं है कि आप एक सामान्य प्रकार को कसना के साथ कैसे लिखेंगे चाहे बाधा एक इंटरफ़ेस या पूर्वज प्रकार से हो।
टेटसुजिन नहीं ओनी

मेरे तर्क के साथ एक जवाब ( stackoverflow.com/a/56304595/4922375 ) जोड़ा गया कि क्यों implementsकुछ नया नहीं लाया जाएगा और आगे चीजों को जटिल करेगा। मुझे उम्मीद है कि यह आपके लिए उपयोगी होगा।
एंड्रयू टोबिल्को

जवाबों:


328

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


@KomodoDave (मुझे लगता है कि उत्तर के आगे की संख्या इसे सही मानती है, मुझे यकीन नहीं है कि अगर इसे चिह्नित करने का कोई अन्य तरीका है, तो कभी-कभी अन्य उत्तरों में अतिरिक्त जानकारी हो सकती है - जैसे मुझे एक विशेष समस्या थी जिसे मैं हल नहीं कर सकता था। जब आप इसे खोज रहे हैं तो Google आपको यहां भेजता है।) @Tetsujin no Oni (क्या यह स्पष्ट करने के लिए कुछ कोड का उपयोग करना संभव होगा? thanx :))
ntg

@ntg, यह एक बहुत अच्छा उदाहरण है उदाहरण की तलाश में एक प्रश्न पर - मैं इसे इस बिंदु पर उत्तर में एम्बेड करने के बजाय, टिप्पणी में लिंक करूंगा। stackoverflow.com/a/6828257/93922
टेटसुजिन नो ओनी

1
मुझे लगता है कि इसका कारण यह है कि कम से कम मैं एक ऐसा जेनेरिक होना चाहूंगा जिसमें एक कंस्ट्रक्टर और तरीके हो सकते हैं जो किसी भी वर्ग को स्वीकार कर सकते हैं कि दोनों एक बेस क्लास का उपयोग करते हैं और एक इंटरफेस का प्रदर्शन करते हैं जो न केवल इंटरफेस का विस्तार करता है। फिर इंटरफेस के परिरक्षण के लिए जेनेरिक परीक्षण की तात्कालिकता है और वास्तविक वर्ग को एक प्रकार के पैरामीटर के रूप में निर्दिष्ट किया गया है। आदर्श रूप से मैं चाहूंगा कि class Generic<RenderableT extends Renderable implements Draggable, Droppable, ...> { Generic(RenderableT toDrag) { x = (Draggable)toDrag; } }कोई व्यक्ति समय की जांच करना चाहे।
पेटकर

1
@peterk और आपको लगता है कि RenderableT के साथ Renderable, Draggable, Droppable का विस्तार होता है .... जब तक मैं यह नहीं समझ पा रहा हूं कि आप क्या चाहते हैं कि erasure जेनरिक आपके लिए ऐसा करे जो यह प्रदान नहीं करता है।
टेटसुजिन नं ओनी

@TetsujinnoOni आप जो चाहते हैं उसमें मैं केवल स्वीकार करने वाले वर्गों के संकलन समय प्रवर्तन के लिए नहीं हूं जो कुछ निश्चित इंटरफेस को लागू करते हैं, और फिर जेबीईसीटी वर्ग (जो उन इंटरफेस को प्रदर्शित करता है) को जेनेरिक में संदर्भित करने में सक्षम हैं और फिर जानते हैं कि कम से कम संकलन समय पर (और रन समय में वांछनीय रूप से) जेनेरिक को सौंपी गई किसी भी चीज को किसी भी निर्दिष्ट इंटरफेस में सुरक्षित रूप से डाला जा सकता है। यह वह स्थिति नहीं है जिस तरह से जावा को अब लागू किया गया है। लेकिन यह अच्छा होगा :)
पेटकर

77

उत्तर यहाँ है  :

एक बंधे हुए प्रकार के पैरामीटर को घोषित करने के लिए, टाइप पैरामीटर का नाम, उसके बाद extendsकीवर्ड, उसके ऊपरी बाउंड […] को सूचीबद्ध करें । ध्यान दें, इस संदर्भ में, फैली हुई का उपयोग सामान्य अर्थ में extends( या तो कक्षाओं में) या implements(इंटरफेस में) के रूप में किया जाता है।

तो वहाँ आपके पास है, यह थोड़ा भ्रमित है, और Oracle इसे जानता है।


1
भ्रम को जोड़ने के लिए getFoo(List<? super Foo> fooList) केवल उस वर्ग के साथ काम करता है जो शाब्दिक रूप से फू द्वारा बढ़ाया जाता है class Foo extends WildcardClass। इस मामले में List<WildcardClass>स्वीकार्य इनपुट होगा। हालाँकि, कोई भी वर्ग जो Fooलागू class Foo implements NonWorkingWildcardClassनहीं List<NonWorkingWildcardClass>होगा, इसका मतलब यह नहीं है कि इसमें मान्य होगा getFoo(List<? super Foo> fooList)। शीशे की तरह साफ!
रे

19

संभवतः क्योंकि दोनों पक्षों (बी और सी) के लिए केवल प्रकार प्रासंगिक है, कार्यान्वयन नहीं। अपने उदाहरण में

public class A<B extends C>{}

बी एक इंटरफ़ेस भी हो सकता है। "फैली" का उपयोग उप-इंटरफेस के साथ-साथ उप-वर्गों को परिभाषित करने के लिए किया जाता है।

interface IntfSub extends IntfSuper {}
class ClzSub extends ClzSuper {}

मैं आमतौर पर के बारे में सोच 'उप फैली सुपर' के रूप में ' उप तरह है सुपर है, लेकिन अतिरिक्त क्षमताओं के साथ', और 'CLZ औजार INTF' के रूप में ' CLZ की एक अहसास है INTF '। आपके उदाहरण में, यह मेल खाएगा: B , C की तरह है , लेकिन अतिरिक्त क्षमताओं के साथ। क्षमताएं यहां प्रासंगिक हैं, बोध नहीं।


10
विचार करें <B D & E> का विस्तार करता है। E <कैप्स> एक वर्ग नहीं होना चाहिए </ caps>।
टॉम हॉल्टिन -

7

यह हो सकता है कि आधार प्रकार एक सामान्य पैरामीटर है, इसलिए वास्तविक प्रकार एक वर्ग का एक इंटरफ़ेस हो सकता है। विचार करें:

class MyGen<T, U extends T> {

क्लाइंट कोड के परिप्रेक्ष्य में भी इंटरफेस लगभग कक्षाओं से अप्रभेद्य हैं, जबकि उपप्रकार के लिए यह महत्वपूर्ण है।


7

यहाँ एक और अधिक शामिल उदाहरण है जहाँ फैली अनुमति है और संभवतः आप क्या चाहते हैं:

public class A<T1 extends Comparable<T1>>


5

यह मनमाने ढंग से उपयोग करने के लिए है। यह किसी भी तरह से हो सकता था। शायद भाषा डिजाइनरों ने "फैली हुई" को सबसे मौलिक शब्द माना है, और इंटरफेस के लिए विशेष मामले के रूप में "लागू होता है"।

लेकिन मुझे लगता है कि implementsइससे थोड़ा और मतलब होगा। मुझे लगता है कि अधिक संचार करता है कि पैरामीटर प्रकारों को एक विरासत संबंध में नहीं होना चाहिए, वे किसी भी प्रकार के उपप्रकार संबंध में हो सकते हैं ।

जावा शब्दावली एक समान दृश्य व्यक्त करती है


3

हमें इसकी आदत है

class ClassTypeA implements InterfaceTypeA {}
class ClassTypeB extends ClassTypeA {}

और इन नियमों से कोई भी मामूली विचलन हमें बहुत भ्रमित करता है।

एक प्रकार से बंधे हुए वाक्य रचना को परिभाषित किया गया है

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

( JLS 12> 4.4। प्रकार चरTypeBound )

यदि हम इसे बदलते तो हम निश्चित रूप से इस implementsमामले को जोड़ते

TypeBound:
    extends TypeVariable 
    extends ClassType {AdditionalBound}
    implements InterfaceType {AdditionalBound}

और दो समान रूप से संसाधित खंडों के साथ समाप्त होता है

ClassOrInterfaceType:
    ClassType 
    InterfaceType

( JLS 12> 4.3। संदर्भ प्रकार और मूल्य>ClassOrInterfaceType )

सिवाय हमें भी ध्यान रखने की आवश्यकता होगी implements, जो आगे चीजों को जटिल करेगा।

मेरा मानना ​​है कि यह मुख्य कारण extends ClassOrInterfaceTypeहै extends ClassTypeऔर implements InterfaceTypeजटिल अवधारणा के भीतर चीजों को सरल रखने के बजाय - और इसका उपयोग किया जाता है । समस्या हम सही शब्द दोनों को कवर करने की जरूरत नहीं है है extendsऔर implementsऔर हम निश्चित रूप से एक को पेश करने नहीं करना चाहती।

<T is ClassTypeA>
<T is InterfaceTypeA>

हालाँकि extendsयह कुछ गड़बड़ लाता है जब यह एक इंटरफ़ेस के साथ जाता है, यह एक व्यापक शब्द है और इसका उपयोग दोनों मामलों का वर्णन करने के लिए किया जा सकता है। अपने दिमाग को एक प्रकार से विस्तारित करने की अवधारणा ( एक वर्ग का विस्तार नहीं, एक इंटरफ़ेस को लागू नहीं करने ) की धुन बनाने की कोशिश करें । आप एक प्रकार के पैरामीटर को दूसरे प्रकार से प्रतिबंधित करते हैं और इससे कोई फर्क नहीं पड़ता कि वास्तव में वह प्रकार क्या है। यह केवल यह मायने रखता है कि यह इसकी ऊपरी सीमा है और यह इसका सुपरपाइप है


-1

वास्तव में, इंटरफ़ेस पर जेनेरिक का उपयोग करते समय, कीवर्ड भी विस्तारित होता है । यहाँ कोड उदाहरण है:

2 वर्ग हैं जो अभिवादन इंटरफ़ेस को लागू करते हैं:

interface Greeting {
    void sayHello();
}

class Dog implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Dog: Hello ");
    }
}

class Cat implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Cat: Hello ");
    }
}

और परीक्षण कोड:

@Test
public void testGeneric() {
    Collection<? extends Greeting> animals;

    List<Dog> dogs = Arrays.asList(new Dog(), new Dog(), new Dog());
    List<Cat> cats = Arrays.asList(new Cat(), new Cat(), new Cat());

    animals = dogs;
    for(Greeting g: animals) g.sayHello();

    animals = cats;
    for(Greeting g: animals) g.sayHello();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.