الأدوية الجيرية: قائمة <؟ يمتد الحيوان> هو نفس القائمة ؟

StackOverflow https://stackoverflow.com/questions/2575363

سؤال

أنا فقط أحاول فهم extends الكلمة الرئيسية في جافا جينك.

List<? extends Animal> يعني أننا نستطيع أن نحسم أي كائن في List أيّ هو Animal

ثم لن يعني ما يلي أيضًا نفس الشيء:

List<Animal>

هل يمكن لأي شخص مساعدتي في معرفة الفرق بين الاثنين أعلاه؟ إلي extends فقط يبدو زائدة عن الحاجة هنا.

شكرًا!

هل كانت مفيدة؟

المحلول

List<Dog> هو نوع فرعي من List<? extends Animal>, ، ولكن ليس نوعا فرعي من List<Animal>.

لماذا List<Dog> ليس نوعًا فرعيًا من List<Animal>؟ النظر في المثال التالي:

void mySub(List<Animal> myList) {
    myList.add(new Cat());
}

إذا سمح لك بتمرير أ List<Dog> إلى هذه الوظيفة ، ستحصل على خطأ في وقت التشغيل.


تحرير: الآن ، إذا استخدمنا List<? extends Animal> بدلاً من ذلك ، سيحدث ما يلي:

void mySub(List<? extends Animal> myList) {
    myList.add(new Cat());     // compile error here
    Animal a = myList.get(0);  // works fine 
}

أنت يستطع تمرير أ List<Dog> إلى هذه الوظيفة ، لكن المترجم يدرك أن إضافة شيء إلى القائمة قد يجعلك في مشكلة. إذا كنت تستخدم super بدلاً من extends (يسمح لك بتمرير أ List<LifeForm>)، على العكس.

void mySub(List<? super Animal> myList) {
    myList.add(new Cat());     // works fine
    Animal a = myList.get(0);  // compile error here, since the list entry could be a Plant
}

النظرية وراء هذا مشارك ومخالفة.

نصائح أخرى

أرى أنك قبلت بالفعل إجابة ، لكنني أود فقط إضافة رأيي ، حيث أعتقد أنني يمكن أن أكون ببعض المساعدة هنا.

الفرق بين List<Animal> و List<? extends Animal> كالتالي.


مع List<Animal>, ، أنت تعرف ما لديك هو بالتأكيد قائمة بالحيوانات. ليس من الضروري أن يكونوا جميعًا في الواقع "حيوانًا - يمكن أيضًا أن يكونوا مستمقين. على سبيل المثال ، إذا كان لديك قائمة بالحيوانات ، فمن المنطقي أن الزوجين يمكن أن يكونا ماعزًا ، وبعضهما القطط ، إلخ - أليس كذلك؟

على سبيل المثال ، هذا صحيح تمامًا:

List<Animal> aL= new List<Animal>();
aL.add(new Goat());
aL.add(new Cat());
Animal a = aL.peek();
a.walk(); // assuming walk is a method within Animal

بالطبع ، ما يلي ليس تكون صالحة:

aL.peek().meow(); // we can't do this, as it's not guaranteed that aL.peek() will be a Cat

مع List<? extends Animal>, ، أنت تدلي ببيان حول نوع القائمة أنت تتعامل مع.

علي سبيل المثال:

List<? extends Animal> L;

هذا في الواقع ليس يمكن إعلان نوع الكائن l كبح. إنه بيان حول أنواع القوائم التي يمكن أن تشير إليها.

على سبيل المثال ، يمكننا القيام بذلك:

L = aL; // remember aL is a List of Animals

ولكن الآن كل المترجم يعرف عن L هو أنه قائمة [إما حيوان أو نوع فرعي للحيوان

حتى الآن ما يلي غير صالح:

L.add(new Animal()); // throws a compiletime error

لأنه على كل ما نعرفه ، يمكن أن يشير L إلى قائمة من الماعز - والتي لا يمكننا إضافة حيوان.

هنا لماذا:

List<Goat> gL = new List<Goat>(); // fine
gL.add(new Goat()); // fine
gL.add(new Animal()); // compiletime error

في ما سبق ، نحاول إلقاء حيوان كماعز. هذا لا يعمل ، لأنه إذا حاولنا بعد القيام بذلك أن نجعل هذا الحيوان يقوم "برأس" ، مثل الماعز؟ لا نعرف بالضرورة أن الحيوان يمكنه فعل ذلك.

ليس. List<Animal> يقول أن القيمة المخصصة لهذا المتغير يجب أن تكون من "النوع" List<Animal>. هذا لا يعني أنه يجب أن يكون هناك فقط Animal الكائنات ، يمكن أن يكون هناك فئات فرعية أيضا.

List<Number> l = new ArrayList<Number>();
l.add(4); // autoboxing to Integer
l.add(6.7); // autoboxing to Double

يمكنك استخدام List<? extends Number> بناء إذا كنت مصلحة في القائمة التي حصلت عليها Number الكائنات ، لكن كائن القائمة نفسه لا يحتاج إلى أن يكون من النوع List<Number> ولكن هل يمكن لأي قائمة أخرى من الفئات الفرعية (مثل List<Integer>).

هذا هو الاستخدام في وقت ما لوسيطات الطريقة التي يمكن أن تقولها "أريد قائمة من Numbers, ، لكنني لا أهتم إذا كان الأمر مجرد List<Number>, ، يمكن أن يكون List<Double> جدا". هذا يتجنب بعض القوالب الغريبة إذا كان لديك قائمة ببعض الفئات الفرعية ، لكن الطريقة تتوقع قائمة من الأساس.

public void doSomethingWith(List<Number> l) {
    ...
}

List<Double> d = new ArrayList<Double>();
doSomethingWith(d); // not working

هذا لا يعمل كما تتوقع List<Number>, ، ليس أ List<Double>. ولكن إذا كتبت List<? extends Number> يمكنك تمرير List<Double> الأشياء حتى لا تكون كذلك List<Number> أشياء.

public void doSomethingWith(List<? extends Number> l) {
    ...
}

List<Double> d = new ArrayList<Double>();
doSomethingWith(d); // works

ملحوظة: هذه الأشياء بأكملها لا علاقة لها براالة الكائنات في القائمة نفسها. لا يزال بإمكانك إضافة Double و Integer الأشياء في أ List<Number> قائمة ، مع أو بدون ? extends أمور.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top