क्या अंतर है <? सुपर ई> और <? ई> का विस्तार करता है?


147

बीच क्या अंतर है <? super E>और <? extends E>?

उदाहरण के लिए जब आप कक्षा को देखते हैं java.util.concurrent.LinkedBlockingQueueतो निर्माणकर्ता के लिए निम्नलिखित हस्ताक्षर होते हैं:

public LinkedBlockingQueue(Collection<? extends E> c)

और विधि के लिए एक के लिए:

public int drainTo(Collection<? super E> c)

जवाबों:


182

पहला कहता है कि यह "कुछ प्रकार है जो ई का पूर्वज है"; दूसरा कहता है कि यह "कुछ प्रकार है जो ई का एक उपवर्ग है"। (दोनों मामलों में E स्वयं ठीक है।)

तो निर्माता का उपयोग करता ? extends Eप्रपत्र तो यह गारंटी देता है कि जब यह हासिल करेगा संग्रह से मूल्यों, वे सभी ई या कुछ उपवर्ग हो जाएगा (यानी वह संगत है)। drainToविधि मूल्यों डाल करने के लिए कोशिश कर रहा है में तो संग्रह का एक तत्व प्रकार होता है, इसलिए संग्रह E या एक सुपर क्लास

एक उदाहरण के रूप में, मान लीजिए कि आपके पास इस तरह एक वर्ग पदानुक्रम है:

Parent extends Object
Child extends Parent

और एक LinkedBlockingQueue<Parent>। आप इस पासिंग का निर्माण कर सकते हैं List<Child>जिसमें सभी तत्वों को सुरक्षित रूप से कॉपी किया जाएगा, क्योंकि हर Childएक माता-पिता है। आप पास नहीं कर सकते List<Object>क्योंकि कुछ तत्व संगत नहीं हो सकते हैं Parent

इसी तरह आप उस कतार को नाली में डाल सकते हैं List<Object>क्योंकि हर Parentएक एक है Object... लेकिन आप इसे सूखा नहीं सकते List<Child>क्योंकि यह List<Child>अपेक्षा करता है कि इसके सभी तत्व संगत हों Child


25
+1। यह वास्तव में व्यावहारिक अंतर है। लाने के लिए फैली हुई है, सुपर डालने के लिए।
यशई 14

1
@ क्या आप पहले पैराग्राफ में (दोनों मामलों में ई ही ठीक है।) का क्या मतलब है?
गीक

2
@ गीक: मेरा मतलब है कि अगर आपके पास कुछ है ? extends InputStreamया ? super InputStreamआप InputStreamतर्क के रूप में उपयोग कर सकते हैं ।
जॉन स्कीट

मुझे वास्तव में जोश ब्लॉक द्वारा प्रभावी जावा में पीईसीएस स्पष्टीकरण नहीं मिला। हालाँकि @Yishai, यह याद रखने में मददगार तरीका है। शायद हम एक नई
महामारी

तो अगर मैं इसे सही पढ़ता हूं, "<? फैली हुई ई>" की आवश्यकता है कि "?" "E" का एक उपवर्ग है, और "<? Super E>" के लिए आवश्यक है कि "E" "?" का उपवर्ग है?
एल सुसाइटर जस्टिसिएरो

130

इसके कारण जावा जेनरिक कैसे लागू होते हैं, इस पर आधारित हैं।

एक उदाहरण उदाहरण

सरणियों के साथ आप ऐसा कर सकते हैं (सरणियाँ सहवर्ती हैं)

Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;

लेकिन, अगर आप ऐसा करने की कोशिश करेंगे तो क्या होगा?

myNumber[0] = 3.14; //attempt of heap pollution

यह अंतिम पंक्ति ठीक-ठीक संकलन करेगी, लेकिन यदि आप इस कोड को चलाते हैं, तो आप ए ArrayStoreException। क्योंकि आप एक पूर्णांक सरणी में एक संख्या डालने की कोशिश कर रहे हैं (एक नंबर संदर्भ के माध्यम से पहुँचा जा रहा है)।

इसका मतलब है कि आप संकलक को मूर्ख बना सकते हैं, लेकिन आप रनटाइम प्रकार प्रणाली को मूर्ख नहीं बना सकते। और ऐसा इसलिए है क्योंकि सरणियाँ वे हैं जिन्हें हम रिफ़ेक्टिव प्रकार कहते हैं । इसका मतलब यह है कि रनटाइम में जावा को पता है कि यह सरणी वास्तव में पूर्णांकों की एक सरणी के रूप में तात्कालिक थी, जो कि केवल प्रकार के संदर्भ के माध्यम से एक्सेस की जाती है Number[]

तो, जैसा कि आप देख सकते हैं, एक चीज वस्तु का वास्तविक प्रकार है, और दूसरी चीज उस संदर्भ का प्रकार है जिसे आप इसे एक्सेस करने के लिए उपयोग करते हैं, है ना?

जावा पीढ़ी के साथ समस्या

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

लेकिन यहां महत्वपूर्ण बिंदु यह है कि चूंकि, रनटाइम के दौरान कोई प्रकार की जानकारी नहीं है, इसलिए यह सुनिश्चित करने का कोई तरीका नहीं है कि हम गंभीर प्रदूषण नहीं कर रहे हैं।

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

List<Integer> myInts = new ArrayList<Integer>();
myInts.add(1);
myInts.add(2);

List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap pollution

यदि जावा कंपाइलर आपको ऐसा करने से नहीं रोकता है, तो रनटाइम टाइप सिस्टम आपको रोक भी नहीं सकता है, क्योंकि रनटाइम पर कोई रास्ता नहीं है, यह निर्धारित करने के लिए कि यह सूची केवल पूर्णांकों की सूची होनी चाहिए थी। जावा रनटाइम आपको इस सूची में जो कुछ भी चाहिए, वह आपको तब डालने देगा, जब इसमें केवल पूर्णांक होना चाहिए, क्योंकि जब इसे बनाया गया था, तो यह पूर्णांकों की सूची के रूप में घोषित किया गया था।

जैसे, जावा के डिजाइनरों ने सुनिश्चित किया कि आप कंपाइलर को बेवकूफ नहीं बना सकते। यदि आप संकलक को बेवकूफ नहीं बना सकते हैं (जैसा कि हम सरणियों के साथ कर सकते हैं) तो आप रनटाइम प्रकार प्रणाली को भी मूर्ख नहीं बना सकते हैं।

इस प्रकार, हम कहते हैं कि सामान्य प्रकार गैर-परिवर्तनीय हैं

जाहिर है, यह बहुरूपता को बाधित करेगा। निम्नलिखित उदाहरण पर विचार करें:

static long sum(Number[] numbers) {
   long summation = 0;
   for(Number number : numbers) {
      summation += number.longValue();
   }
   return summation;
}

अब आप इसे इस तरह इस्तेमाल कर सकते हैं:

Integer[] myInts = {1,2,3,4,5};
Long[] myLongs = {1L, 2L, 3L, 4L, 5L};
Double[] myDoubles = {1.0, 2.0, 3.0, 4.0, 5.0};

System.out.println(sum(myInts));
System.out.println(sum(myLongs));
System.out.println(sum(myDoubles));

लेकिन अगर आप सामान्य कोड के साथ समान कोड लागू करने का प्रयास करते हैं, तो आप सफल नहीं होंगे:

static long sum(List<Number> numbers) {
   long summation = 0;
   for(Number number : numbers) {
      summation += number.longValue();
   }
   return summation;
}

यदि आप ...

List<Integer> myInts = asList(1,2,3,4,5);
List<Long> myLongs = asList(1L, 2L, 3L, 4L, 5L);
List<Double> myDoubles = asList(1.0, 2.0, 3.0, 4.0, 5.0);

System.out.println(sum(myInts)); //compiler error
System.out.println(sum(myLongs)); //compiler error
System.out.println(sum(myDoubles)); //compiler error

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

सहप्रसरण

सहसंयोजक के साथ आप एक संरचना से आइटम पढ़ सकते हैं, लेकिन आप इसमें कुछ भी नहीं लिख सकते हैं। ये सभी वैध घोषणाएं हैं।

List<? extends Number> myNums = new ArrayList<Integer>();
List<? extends Number> myNums = new ArrayList<Float>();
List<? extends Number> myNums = new ArrayList<Double>();

और आप इससे पढ़ सकते हैं myNums:

Number n = myNums.get(0); 

क्योंकि आप यह सुनिश्चित कर सकते हैं कि वास्तविक सूची में जो कुछ भी है, उसे एक संख्या तक सीमित किया जा सकता है (आखिर कुछ भी जो संख्या का विस्तार करता है वह संख्या है, सही?)

हालाँकि, आपको एक सहसंयोजक संरचना में कुछ भी डालने की अनुमति नहीं है।

myNumst.add(45L); //compiler error

यह अनुमति नहीं दी जाएगी, क्योंकि जावा यह गारंटी नहीं दे सकता है कि जेनेरिक संरचना में वस्तु का वास्तविक प्रकार क्या है। यह कुछ भी हो सकता है जो संख्या का विस्तार करता है, लेकिन संकलक निश्चित नहीं हो सकता है। इसलिए आप पढ़ सकते हैं, लेकिन लिख नहीं सकते।

contravariance

विपरीतता के साथ आप इसके विपरीत कर सकते हैं। आप चीजों को एक सामान्य संरचना में रख सकते हैं, लेकिन आप इसे पढ़ नहीं सकते।

List<Object> myObjs = new List<Object>();
myObjs.add("Luke");
myObjs.add("Obi-wan");

List<? super Number> myNums = myObjs;
myNums.add(10);
myNums.add(3.14);

इस मामले में, वस्तु की वास्तविक प्रकृति वस्तुओं की एक सूची है, और विरोधाभासी के माध्यम से, आप संख्याओं को इसमें डाल सकते हैं, मूल रूप से क्योंकि सभी संख्याओं में उनके सामान्य पूर्वजों के रूप में ऑब्जेक्ट हैं। जैसे, सभी संख्याएँ ऑब्जेक्ट हैं, और इसलिए यह मान्य है।

हालाँकि, आप इस संदर्भात्मक संरचना से सुरक्षित रूप से कुछ भी नहीं पढ़ सकते हैं यह मानते हुए कि आपको एक नंबर मिलेगा।

Number myNum = myNums.get(0); //compiler-error

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

जाओ / सिद्धांत रखो

इस प्रकार, सहसंयोजक का उपयोग करें जब आप केवल एक संरचना से जेनेरिक मान लेने का इरादा रखते हैं, तो कॉन्ट्रोवर्सी का उपयोग करें जब आप केवल एक संरचना में जेनेरिक मान रखने का इरादा रखते हैं और सटीक जेनेरिक प्रकार का उपयोग करते हैं जब आप दोनों करने का इरादा रखते हैं।

मेरे पास सबसे अच्छा उदाहरण निम्नलिखित है जो किसी भी प्रकार की संख्याओं को एक सूची से दूसरी सूची में कॉपी करता है। यह केवल हो जाता है स्रोत से आइटम, और यह केवल डालता लक्ष्य में आइटम नहीं है।

public static void copy(List<? extends Number> source, List<? super Number> target) {
    for(Number number : source) {
        target(number);
    }
}

इस तरह के मामले के लिए सहसंयोजक और विरोधाभासी की शक्तियों के लिए यह काम करता है:

List<Integer> myInts = asList(1,2,3,4);
List<Double> myDoubles = asList(3.14, 6.28);
List<Object> myObjs = new ArrayList<Object>();

copy(myInts, myObjs);
copy(myDoubles, myObjs);

27
इस जवाब को शीर्ष पर टक्कर देना चाहिए। अच्छी व्याख्या।
सुरेश अट्टा

1
@edwindalorzo, एक छोटा टाइपो है जिसे आप कंट्रोवर्सी के तहत ठीक करना चाहते हैं। आप कहते हैं List<Object> myObjs = new List<Object();(जो >दूसरे के लिए समापन को याद कर रहा है Object)।

इन सूक्ष्म अवधारणाओं के शानदार, आसान और स्पष्ट उदाहरण!
db1234

कुछ आप दूसरों को चीजों को याद रखने में मदद करने के लिए जोड़ सकते हैं। जब आप किसी सुपर क्लास से एक विधि को कॉल करना चाहते हैं, तो आप उपयोग करते हैं super.methodName। उपयोग करते समय <? super E>, इसका अर्थ है " superदिशा में कुछ " जैसा कि extendsदिशा में कुछ के विपरीत है । उदाहरण: Objectमें है superकी दिशा Number(क्योंकि यह एक सुपर वर्ग है) और Integerमें है extends(क्योंकि यह फैली दिशा Number)।
BrainStorm.exe

59

<? extends E>Eऊपरी सीमा के रूप में परिभाषित करता है : "यह डाली जा सकती है E"।

<? super E>Eनिचली सीमा के रूप में परिभाषित किया गया है: " Eइसे कास्ट किया जा सकता है।"


6
यह मेरे द्वारा देखे गए अंतर का सबसे अच्छा सरल / व्यावहारिक सारांश है।
JAB

1
के लिए दशकों अब (OOP के साथ) मैं विचार "ऊपरी" का एक सहज उलट लड़ रहा है और "कम"। उत्तेजक! मेरे लिए, Objectमूल रूप से एक निम्न स्तर की श्रेणी है, इसके बावजूद कि यह परम सुपरक्लास के रूप में है (और UML या इसी तरह के वंशानुगत पेड़ों में खड़ी है)। मैं कभी कोशिश करने के बावजूद इसे पूर्ववत नहीं कर पाया।

3
@ tgm1024 "सुपरक्लास" और "सबक्लास" आपको बहुत तकलीफ देते हैं।
डेविड मोल्स

@ डेविड, क्यों? आप स्पष्ट रूप से इस बात का पालन नहीं कर रहे हैं कि मैं क्या कह रहा हूं। "सुपरक्लास" "सुपरसेट" के समान है; विशेषज्ञता की धारणा आईएस-ए संबंध के तहत प्रयोज्यता में कमी है। सेब IS-A Fruit फल (सुपरक्लास) एक सुपरसेट है जिसमें एक उपसमूह के रूप में एप्पल (उपवर्ग) शामिल है। वह मौखिक संबंध ठीक है। मैं जो कह रहा हूं वह टूटता है यह धारणा है कि "ऊपरी" और "निचले" में "सुपरसेट" और "सबसेट" के लिए आंतरिक मैपिंग है। ऊ और लोअर को ओओ में शर्तों के रूप में टाला जाना चाहिए।

1
@ tgm1024 "सुपर-" लैटिन सुपर "से ऊपर", और "उप-" लैटिन उप से "नीचे, नीचे" आता है। यही कहना है, etymologically, सुपर ऊपर है और उप नीचे है।
डेविड मोल्स

12

मैं कोशिश कर रहा हूं और इसका जवाब दूंगा। लेकिन वास्तव में अच्छा जवाब पाने के लिए आपको जोशुआ बलोच की किताब इफेक्टिव जावा (दूसरा संस्करण) की जांच करनी चाहिए। वह एमनेमिक PECS का वर्णन करता है, जो "निर्माता के विस्तार, उपभोक्ता सुपर" के लिए खड़ा है।

विचार यह है कि यदि आप कोड ऑब्जेक्ट से जेनेरिक मानों का उपभोग कर रहे हैं तो आपको एक्सटेंड्स का उपयोग करना चाहिए। लेकिन अगर आप जेनेरिक प्रकार के लिए नए मान पैदा कर रहे हैं तो आपको सुपर का उपयोग करना चाहिए।

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

public void pushAll(Iterable<? extends E> src) {
  for (E e: src) 
    push(e);
}

तथा

public void popAll(Collection<? super E> dst) {
  while (!isEmpty())
    dst.add(pop())
}

लेकिन वास्तव में आपको इस पुस्तक को देखना चाहिए: http://java.sun.com/docs/books/effective/



7

आप contravariance ( ) और covariance ( ) की शर्तों के लिए Google करना चाह सकते हैं । मैंने पाया कि जेनेरिक को समझने के लिए सबसे उपयोगी चीज मेरे लिए विधि हस्ताक्षर को समझना था :<? super E><? extends E>Collection.addAll

public interface Collection<T> {
    public boolean addAll(Collection<? extends T> c);
}

जैसा कि आप एक Stringको जोड़ने में सक्षम होना चाहते हैं List<Object>:

List<Object> lo = ...
lo.add("Hello")

आपको विधि के माध्यम से एक List<String>(या एस के किसी भी संग्रह String) को जोड़ने में सक्षम होना चाहिए addAll:

List<String> ls = ...
lo.addAll(ls)

हालाँकि आपको महसूस करना चाहिए कि a List<Object>और a List<String>समतुल्य नहीं हैं और न ही बाद वाला पूर्व का उपवर्ग है। क्या जरूरत है एक सहसंयोजक प्रकार के पैरामीटर की अवधारणा - यानी <? extends T>बिट।

एक बार जब आपके पास यह होता है, तो ऐसे परिदृश्यों के बारे में सोचना आसान होता है जहाँ आप विरोधाभासी भी चाहते हैं ( Comparableइंटरफ़ेस की जाँच करें)।


4

उत्तर से पहले; कृपया स्पष्ट हो कि

  1. सामान्य लोग केवल TYPE_SAFETY सुनिश्चित करने के लिए समय सुविधा का संकलन करते हैं, यह RUNTIME के ​​दौरान उपलब्ध नहीं होगा।
  2. केवल जेनरिक के साथ एक संदर्भ प्रकार की सुरक्षा को मजबूर करेगा; यदि संदर्भ जेनरिक के साथ घोषित नहीं किया जाता है तो यह बिना किसी प्रकार की सुरक्षा के काम करेगा।

उदाहरण:

List stringList = new ArrayList<String>();
stringList.add(new Integer(10)); // will be successful.

आशा है कि यह आपको वाइल्डकार्ड को अधिक स्पष्ट रूप से समझने में मदद करेगा।

//NOTE CE - Compilation Error
//      4 - For

class A {}

class B extends A {}

public class Test {

    public static void main(String args[]) {

        A aObj = new A();
        B bObj = new B();

        //We can add object of same type (A) or its subType is legal
        List<A> list_A = new ArrayList<A>();
        list_A.add(aObj);
        list_A.add(bObj); // A aObj = new B(); //Valid
        //list_A.add(new String()); Compilation error (CE);
        //can't add other type   A aObj != new String();


        //We can add object of same type (B) or its subType is legal
        List<B> list_B = new ArrayList<B>();
        //list_B.add(aObj); CE; can't add super type obj to subclass reference
        //Above is wrong similar like B bObj = new A(); which is wrong
        list_B.add(bObj);



        //Wild card (?) must only come for the reference (left side)
        //Both the below are wrong;   
        //List<? super A> wildCard_Wrongly_Used = new ArrayList<? super A>();
        //List<? extends A> wildCard_Wrongly_Used = new ArrayList<? extends A>();


        //Both <? extends A>; and <? super A> reference will accept = new ArrayList<A>
        List<? super A> list_4__A_AND_SuperClass_A = new ArrayList<A>();
                        list_4__A_AND_SuperClass_A = new ArrayList<Object>();
                      //list_4_A_AND_SuperClass_A = new ArrayList<B>(); CE B is SubClass of A
                      //list_4_A_AND_SuperClass_A = new ArrayList<String>(); CE String is not super of A  
        List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<A>();
                          list_4__A_AND_SubClass_A = new ArrayList<B>();
                        //list_4__A_AND_SubClass_A = new ArrayList<Object>(); CE Object is SuperClass of A


        //CE; super reference, only accepts list of A or its super classes.
        //List<? super A> list_4__A_AND_SuperClass_A = new ArrayList<String>(); 

        //CE; extends reference, only accepts list of A or its sub classes.
        //List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<Object>();

        //With super keyword we can use the same reference to add objects
        //Any sub class object can be assigned to super class reference (A)                  
        list_4__A_AND_SuperClass_A.add(aObj);
        list_4__A_AND_SuperClass_A.add(bObj); // A aObj = new B();
        //list_4__A_AND_SuperClass_A.add(new Object()); // A aObj != new Object(); 
        //list_4__A_AND_SuperClass_A.add(new String()); CE can't add other type

        //We can't put anything into "? extends" structure. 
        //list_4__A_AND_SubClass_A.add(aObj); compilation error
        //list_4__A_AND_SubClass_A.add(bObj); compilation error
        //list_4__A_AND_SubClass_A.add("");   compilation error

        //The Reason is below        
        //List<Apple> apples = new ArrayList<Apple>();
        //List<? extends Fruit> fruits = apples;
        //fruits.add(new Strawberry()); THIS IS WORNG :)

        //Use the ? extends wildcard if you need to retrieve object from a data structure.
        //Use the ? super wildcard if you need to put objects in a data structure.
        //If you need to do both things, don't use any wildcard.


        //Another Solution
        //We need a strong reference(without wild card) to add objects 
        list_A = (ArrayList<A>) list_4__A_AND_SubClass_A;
        list_A.add(aObj);
        list_A.add(bObj);

        list_B = (List<B>) list_4__A_AND_SubClass_A;
        //list_B.add(aObj); compilation error
        list_B.add(bObj);

        private Map<Class<? extends Animal>, List<? extends Animal>> animalListMap;

        public void registerAnimal(Class<? extends Animal> animalClass, Animal animalObject) {

            if (animalListMap.containsKey(animalClass)) {
                //Append to the existing List
                 /*    The ? extends Animal is a wildcard bounded by the Animal class. So animalListMap.get(animalObject);
                 could return a List<Donkey>, List<Mouse>, List<Pikachu>, assuming Donkey, Mouse, and Pikachu were all sub classes of Animal. 
                 However, with the wildcard, you are telling the compiler that you don't care what the actual type is as long as it is a sub type of Animal.      
                 */   
                //List<? extends Animal> animalList = animalListMap.get(animalObject);
                //animalList.add(animalObject);  //Compilation Error because of List<? extends Animal>
                List<Animal> animalList = animalListMap.get(animalObject);
                animalList.add(animalObject);      


            } 
    }

    }
}

इन्हें भी देखें @Dana stackoverflow.com/questions/15255929/...
Kanagavelu Sugumar

जेनेरिक श्रेणी के प्रकार पर मेरा जवाब stackoverflow.com/questions/462297/how-to-use-classt-in-java/…
Kanagavelu Sugumar

1
कोड के साथ अच्छी व्याख्या। लेकिन अगर आपने कोड ब्लॉक के बाहर कोड में टिप्पणियों का उपयोग किया था, तो यह देखने और अधिक पठनीय के लिए बेहतर होगा।
प्रभु

3

ऊपरी बाउंड वाला एक वाइल्डकार्ड "प्रकार का विस्तार करता है" जैसा दिखता है और सभी प्रकार के परिवार के लिए खड़ा होता है जो प्रकार के उपप्रकार होते हैं, प्रकार प्रकार शामिल किया जा रहा है। टाइप को अपर बाउंड कहा जाता है।

कम बाउंड वाला एक वाइल्डकार्ड "सुपर टाइप" जैसा दिखता है और सभी प्रकार के परिवार के लिए खड़ा है जो टाइप के सुपरपाइप हैं, टाइप टाइप शामिल हैं। प्रकार को निचला बाउंड कहा जाता है।


1

आपके पास एक पैरेंट क्लास और एक चाइल्ड क्लास है, जो पेरेंट क्लास से विरासत में मिली है। पेरेंट क्लास को ग्रैंडपेरेंट क्लास नामक एक अन्य क्लास से विरासत में मिला है। इन ऑर्डर ऑफ इनहेरिटेंस ग्रैंडपैरेंट> पैरेंट> चाइल्ड है। अब, <? पैरंट्स का विस्तार> - यह पेरेंट क्लास या चाइल्ड क्लास <स्वीकार करता है? सुपर पेरेंट> - यह पेरेंट क्लास या फिर ग्रैंडपैरेंट क्लास को स्वीकार करता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.