Skirtumas tarp <? super t> ir <? pratęsia T> į „Java“

Koks skirtumas tarp List<? super T> List<? super T> ir List<? extends T> List<? extends T> ?

Aš naudoju List<? extends T> List<? extends T> , tačiau neleidžia į jį įtraukti elementų list.add(e) , o List<? super T> List<? super T> daro.

599
03 дек. Anandas nustatytas gruodžio 3 d. 2010-12-03 09:57 '10, 9:57, 2010-12-03 09:57
@ 15 atsakymų

extends

Laukinių ženklų deklaracijos List<? extends Number> foo3 List<? extends Number> foo3 reiškia, kad bet kuris iš jų yra teisinis priskyrimas:

 List<? extends Number> foo3 = new ArrayList<Number>(); // Number "extends" Number (in this context) List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number List<? extends Number> foo3 = new ArrayList<Double>(); // Double extends Number 
  • Skaitymas Atsižvelgiant į pirmiau nurodytus uždavinius, kokio tipo objektas jums bus užtikrintas skaityti iš List foo3 :

    • Galite skaityti „ Number , nes bet kuris iš sąrašų, kuriuos galima priskirti „ foo3 yra „ Number arba „ foo3 “ poklasis.
    • Jūs negalite skaityti „ Integer , nes „ foo3 gali nukreipti į List<Double> .
    • Negalite skaityti „ Double , nes „ foo3 gali nukreipti į „ List<Integer> .
  • Rašymas Atsižvelgiant į pirmiau minėtas užduotis, kokio tipo objektą pridėtumėte prie List foo3 , kuris būtų teisėtas visoms pirmiau nurodytoms galimoms „ ArrayList užduotims:

    • Jūs negalite pridėti Integer , nes foo3 gali nukreipti į List<Double> .
    • Negalite pridėti Double , nes foo3 gali nukreipti į List<Integer> .
    • Negalite pridėti Number , nes foo3 gali nukreipti į List<Integer> .

Jūs negalite pridėti jokių objektų į List<? extends T> List<? extends T> , nes negalite garantuoti, kokio tipo List jis iš tikrųjų rodo, todėl negalite garantuoti, kad objektas yra leidžiamas List . Vienintelė „garantija“ yra ta, kad jūs galite ją perskaityti tik T ir T arba subklasę T

super

Dabar apsvarstykite List <? super T> List <? super T> .

Laukinių ženklų deklaracijos List<? super Integer> foo3 List<? super Integer> foo3 reiškia, kad bet kuris iš jų yra teisinis tikslas:

 List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context) List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer 
  • Skaitymas Atsižvelgiant į pirmiau nurodytas užduotis, kokio tipo objektą garantuojate, kai skaitote iš List foo3 :

    • foo3 nėra jums garantuotas, nes foo3 gali nukreipti į List<Number> arba List<Object> .
    • foo3 Number , nes foo3 gali nukreipti į List<Object> .
    • Garantija yra ta, kad gausite Object ar Object poklasio egzempliorių (bet nežinote, kuris poklasis).
  • Rašymas Atsižvelgiant į pirmiau minėtas užduotis, kokio tipo objektą pridėtumėte prie List foo3 , kuris būtų teisėtas visoms pirmiau nurodytoms galimoms „ ArrayList užduotims:

    • Galite pridėti „ Integer nes bet kuriame iš pirmiau pateiktų sąrašų leidžiama „ Integer .
    • Galite pridėti „ Integer poklasio egzempliorių, nes bet kurio iš pirmiau pateiktų sąrašų yra leidžiamas „ Integer poklasio egzempliorius.
    • Negalite pridėti Double , nes foo3 gali nukreipti į ArrayList<Integer> .
    • Negalite pridėti Number , nes foo3 gali nukreipti į ArrayList<Integer> .
    • Negalite pridėti Object , nes foo3 gali nukreipti į ArrayList<Integer> .

Pecs

Prisiminkite „PECS“: „Gamintojų skatinimas, vartotojų Super“.

  • "Gamintojas praplečia" . Jei jums reikia List kad sukurtumėte T reikšmes (norite skaityti T iš sąrašo), ar turite ją paskelbti ? extends T ? extends T , pvz., List<? extends Integer> List<? extends Integer> . Bet jūs negalite pridėti prie šio sąrašo.

  • „Vartotojų super“. Jei jums reikia List kad galėtumėte naudoti T reikšmes (norite įrašyti T į sąrašą), ar turite ją paskelbti ? super T ? super T , pavyzdžiui, List<? super Integer> List<? super Integer> . Tačiau nėra jokių garantijų, kokio tipo objektą galite skaityti iš šio sąrašo.

  • Jei reikia skaityti ir rašyti į sąrašą, turite tai tiksliai deklaruoti be jokių vietinių simbolių. List<Integer> .

Pavyzdys

Pažymėkite šį pavyzdį iš dažnai užduodamų „Java Generics“ klausimų . Atkreipkite dėmesį, kad src (gamintojų sąraše) šaltinių sąraše extends naudojamas ir paskirties vietos sąraše (suvartojamų prekių sąrašas) naudojamas super :

 public class Collections { public static <T> void copy(List<? super T> dest, List<? extends T> src) { for (int i = 0; i < src.size(); i++) dest.set(i, src.get(i)); } } 

Taip pat žr. Kaip įtraukti į sąrašą <? plečia> duomenų struktūras?

1130
03 дек. atsakymas pateikiamas Bert F 03 d. 2010-12-03 11:03 '10, 11:03, 2010-12-03 11:03

Įsivaizduokite, kad ši hierarchija

2019

21 окт. Luigi Cortese atsakymas spalio 21 d 2015-10-21 00:16 '15 prie 0:16 2015-10-21 00:16

Man patinka atsakymas iš @Bert F, bet taip mato mano smegenys.

Aš turiu X ranką. Jei noriu įrašyti savo X į sąrašą, šis sąrašas turėtų būti arba X sąrašas, arba sąrašas dalykų, kuriuos mano X gali būti upcast, kai juos parašysiu, t.y. bet kokia X klasė ...

 List<? super X> 

Jei gaunu sąrašą ir noriu skaityti X iš šio sąrašo, geriau būti X sąrašo arba dalykų, kuriuos X, kai juos perskaitysiu, sąrašas, t. Y. viskas, kas tęsiasi X

 List<? extends X> 

Tikiuosi, kad tai padės.

58
04 дек. Michael Dausmann atsakymas gruodžio 04 2015-12-04 01:05 '15, 01:05 2015-12-04 01:05

Remiantis atsakymu Bert F norėčiau paaiškinti savo supratimą.

Tarkime, kad turime 3 klases

 public class Fruit{} public class Melon extends Fruit{} public class WaterMelon extends Melon{} 

Čia mes turime

 List<? extends Fruit> fruitExtendedList = … //Says that I can be a list of any object as long as this object extends Fruit. 

Dabar pabandykime gauti vertę iš vaisiųExtendedList

 Fruit fruit = fruitExtendedList.get(position) //This is valid as it can only return Fruit or its subclass. 

Pabandykite dar kartą

 Melon melon = fruitExtendedList.get(position) //This is not valid because fruitExtendedList can be a list of Fruit only, it may not be //list of Melon or WaterMelon and in java we cannot assign sub class object to //super class object reference without explicitly casting it. 

Tas pats pasakytina ir apie

 WaterMelon waterMelon = fruitExtendedList.get(position) 

Dabar pabandykite nustatyti tam tikrą objektą į „TreeExtendedList“

Įdėjus vaisių objektą

 fruitExtendedList.add(new Fruit()) //This in not valid because as we know fruitExtendedList can be a list of any //object as long as this object extends Fruit. So what if it was the list of //WaterMelon or Melon you cannot add Fruit to the list of WaterMelon or Melon. 

Melono objekto pridėjimas

 fruitExtendedList.add(new Melon()) //This would be valid if fruitExtendedList was the list of Fruit but it may //not be, as it can also be the list of WaterMelon object. So, we see an invalid //condition already. 

Galiausiai pabandykite pridėti „WaterMelon“ objektą.

 fruitExtendedList.add(new WaterMelon()) //Ok, we got it now we can finally write to fruitExtendedList as WaterMelon //can be added to the list of Fruit or Melon as any superclass reference can point //to its subclass object. 

Bet palaukite , jei kas nors nuspręs, kad „SaltyLemon“ argumentams, pavyzdžiui, būtų sukurtas naujas „Lemon“ tipas

 public class SaltyLemon extends Lemon{} 

„FruitExtendedList“ dabar gali būti „Vaisių, melionų,„ WaterMelon “arba„ SaltyLemon “sąrašas.

Taigi, mūsų pareiškimas

 fruitExtendedList.add(new WaterMelon()) 

neteisingas.

Iš esmės mes galime pasakyti, kad negalime nieko rašyti faile „failai“.

Apibendrina List<? extends Fruit> List<? extends Fruit>

Dabar žiūrėkite

 List<? super Melon> melonSuperList= … //Says that I can be a list of anything as long as its object has super class of Melon. 

Dabar pabandykime gauti tam tikrą vertę iš melonSuperList

 Fruit fruit = melonSuperList.get(position) //This is not valid as melonSuperList can be a list of Object as in java all //the object extends from Object class. So, Object can be super class of Melon and //melonSuperList can be a list of Object type 

Panašiai meliono, „WaterMelon“ ar bet kurio kito objekto negalima skaityti.

Tačiau atkreipkite dėmesį, kad galime skaityti objekto tipo atvejus.

 Object myObject = melonSuperList.get(position) //This is valid because Object cannot have any super class and above statement //can return only Fruit, Melon, WaterMelon or Object they all can be referenced by //Object type reference. 

Dabar pabandykite nustatyti tam tikrą reikšmę iš melonSuperList.

Objekto tipo objekto pridėjimas

 melonSuperList.add(new Object()) //This is not valid as melonSuperList can be a list of Fruit or Melon. //Note that Melon itself can be considered as super class of Melon. 

Įrašyta „Fruit“ tipo objektas

 melonSuperList.add(new Fruit()) //This is also not valid as melonSuperList can be list of Melon 

Pridėti meliono objektą

 melonSuperList.add(new Melon()) //This is valid because melonSuperList can be list of Object, Fruit or Melon and in //this entire list we can add Melon type object. 

Įrašomas WaterMelon tipo objektas

 melonSuperList.add(new WaterMelon()) //This is also valid because of same reason as adding Melon 

Apibendrinant galima pasakyti, kad meloną ar jo poklasį galime pridėti melonSuperList ir tik Objekto objektą.

17
19 марта '16 в 11:08 2016-03-19 11:08 atsakymas duotas Sushant kovo 19, 16, 11:08 2016-03-19 11:08

super - apatinė riba ir tęsiniai - viršutinė riba.

Pagal http://download.oracle.com/javase/tutorial/extra/generics/morefun.html :

Sprendimas yra naudoti ribotą pakaitos simbolį, kurio dar nesate matę: pakaitos simboliai su apatine riba. sintaksė? super T žymi nežinomą tipą, kuris yra T (arba T pats) supertype, prisiminkite, kad supernas yra refleksinis ryšys. Tai yra dvigubai ribota pakaitos simbolis, kurią naudojome, kur mes naudojame? pratęsia T, kuris žymi nežinomą tipą, kuris yra T. potipis.

14
03 дек. atsakymas duotas Istao 03 dec. 2010-12-03 10:04 '10 10:04 val. 2010-12-03 10:04

Naudodami plėtinius galite gauti tik iš kolekcijos. Jūs negalite įterpti į jį. Be to, nors „ super“ leidžia jums gauti ir pristatyti grąžinimo tipą gavimo metu ? super t.

3
28 янв. Atsakyti Sai Sunder Jan 28 2014-01-28 09:51 '14 at 9:51 2014-01-28 09:51

Labiausiai painus dalykas yra tai, kad bet kokie apribojimai, kuriuos mes nurodome, priskyrimas veikia tik vienu būdu:

 baseClassInstance = derivedClassInstance; 

Galbūt manote, kad „ Integer extends Number ir ką „ Integer atliks kaip <? extends Number> <? extends Number> , bet kompiliatorius jums tai pasakys <? extends Number> cannot be converted to Integer <? extends Number> cannot be converted to Integer (tai yra žmogaus kalba, neteisinga, kad viskas, kas pratęsia numerį, gali būti konvertuojama į Integer):

 class Holder<T> { T v; T get() { return v; } void set(T n) { v=n; } } class A { public static void main(String[]args) { Holder<? extends Number> he = new Holder(); Holder<? super Number> hs = new Holder(); Integer i; Number n; Object o; // Producer Super: always gives an error except // when consumer expects just Object i = hs.get(); // <? super Number> cannot be converted to Integer n = hs.get(); // <? super Number> cannot be converted to Number // <? super Number> cannot be converted to ... (but // there is no class between Number and Object) o = hs.get(); // Consumer Super hs.set(i); hs.set(n); hs.set(o); // Object cannot be converted to <? super Number> // Producer Extends i = he.get(); // <? extends Number> cannot be converted to Integer n = he.get(); o = he.get(); // Consumer Extends: always gives an error he.set(i); // Integer cannot be converted to <? extends Number> he.set(n); // Number cannot be converted to <? extends Number> he.set(o); // Object cannot be converted to <? extends Number> } } 

hs.set(i); gerai, nes Integer gali būti konvertuojamas į bet kokią superklasę iš Number (o ne todėl, kad Integer yra skaičiaus viršūnių klasė, kuri nėra tiesa).

EDIT pridėjo komentarą apie „Consumer Extends“ ir „Producer Super“ - jie neturi prasmės, nes jie nenurodo atitinkamai nieko ir tiesiog Object . Patartina prisiminti PECS, nes CEPS niekada nėra naudinga.

2
08 июля '16 в 18:11 2016-07-08 18:11 atsakymas duotas 18446744073709551615 liepos 8 '16, 18:11 2016-07-08 18:11

Kada naudoti pratęsiama ir super

Ženklai yra naudingiausi metodų parametruose. Jie suteikia būtiną lankstumą metodų sąsajose.

Žmonės dažnai supainioti, kada naudoti plėtinius ir kada naudoti super sienas. Nykščio taisyklė yra „get-put“ principas. Jei kažką gausite iš parametruoto konteinerio, naudokite.

 int totalFuel(List<? extends Vehicle> list) { int total = 0; for(Vehicle v : list) { total += v.getFuel(); } return total;} 

TotalFuel metodas gauna transporto priemones iš sąrašo, klausia, kiek kuro jie turi, ir apskaičiuoja bendrą kiekį. Jei objektus įdedate į parametruotą konteinerį, naudokite super.

 int totalValue(Valuer<? super Vehicle> valuer) { int total = 0; for(Vehicle v : vehicles) { total += valuer.evaluate(v); } return total;} 

„TotalValue“ metodas „Automobiliai“ įkelia į vertintoją. Naudinga žinoti, kad pririšimas yra daug dažniau nei super.

1
02 июня '17 в 1:20 2017-06-02 01:20 „ Kevin STS“ atsakymas birželio 2 d. 17 d. 1:20 2017-06-02 01:20

Atsakymų balso atsakymai apima daugelį aspektų. Tačiau aš stengiuosi atsakyti kitaip.

Turime apsvarstyti 2 dalykus

1. Sąrašo kintamojo priskyrimas

List<? extends X> listvar;

Čia gali būti priskirtas bet kuris X sąrašas arba X poklasių sąrašas .

List<? extends Number> listvar; listvar = new ArrayList<Number>(); listvar = new ArrayList<Integer>();


List<? super X> listvar;

Čia gali būti priskirtas bet kuris X arba X superklasės sąrašas .

List<? super Number> listvar; listvar = new ArrayList<Number>(); listvar = new ArrayList<Object>();

2. Atlikite skaitymo ar rašymo operaciją sąrašo kintamajame.

 'List<? extends X> listvar;' 

Šią funkciją galite naudoti, kad priimtumėte metodo argumentų sąrašą ir atliktumėte bet kokias operacijas su X tipu (Pastaba: iš sąrašo galite skaityti tik X tipo objektus ).

 'List<? super Number> listvar; 

Šią funkciją galite naudoti, kad priimtumėte metodo argumentų sąrašą ir atliktumėte bet kokias operacijas su Objekto tipu, nes sąraše galite skaityti tik Objektus . Bet taip, čia dar vienas dalykas, į sąrašą galite pridėti X tipo objektus.

1
31 марта '18 в 7:20 2018-03-31 07:20 atsakymą pateikė „ Shailesh Pratapwar “ kovo 31 d. 18 val.

Sąrašas <? pratęsia X> neleidžia į sąrašą įtraukti nieko, išskyrus nulį.

Sąrašas <? super X> leidžia jums pridėti viską, kas yra - X (X arba jo poklasis), arba null.

1
28 сент. atsakymas pateikiamas elyor 28 sep . 2017-09-28 15:44 '17, 15:44 pm 2017-09-28 15:44

Norėčiau vizualizuoti šį skirtumą. Tarkime, mes turime:

 class A { } class B extends A { } class C extends B { } 

List<? extends T> List<? extends T> List<? extends T> List<? extends T> - skaityti ir priskirti:

 |-------------------------|-------------------|---------------------------------| | wildcard | get | assign | |-------------------------|-------------------|---------------------------------| | List<? extends C> | ABC | List<C> | |-------------------------|-------------------|---------------------------------| | List<? extends B> | AB | List<B> List<C> | |-------------------------|-------------------|---------------------------------| | List<? extends A> | A | List<A> List<B> List<C> | |-------------------------|-------------------|---------------------------------| 

List<? super T> List<? super T> List<? super T> List<? super T> - įrašymas ir priskyrimas:

 |-------------------------|-------------------|--------------------------------------------| | wildcard | add | assign | |-------------------------|-------------------|--------------------------------------------| | List<? super C> | C | List<Object> List<A> List<B> List<C> | |-------------------------|-------------------|--------------------------------------------| | List<? super B> | BC | List<Object> List<A> List<B> | |-------------------------|-------------------|--------------------------------------------| | List<? super A> | ABC | List<Object> List<A> | |-------------------------|-------------------|--------------------------------------------| 

Visais atvejais:

  • visada galite gauti Object iš sąrašo, nepriklausomai nuo šablono.
  • Nepriklausomai nuo šablono, kintamųjų sąraše visada galite pridėti null .
1
23 сент. Atsakymas pateikiamas Oleksandr 23 rugsėjis 2018-09-23 20:46 '18, 08:46 pm 2018-09-23 20:46

Galite peržiūrėti visus aukščiau pateiktus atsakymus, kad pamatytumėte, kodėl .add() apribotas '<?>' , '<? extends>' '<? extends>' ir natūra iki '<? super>' '<? super>' .

Tačiau čia visa tai daroma, jei norite ją prisiminti ir nenorite kiekvieną kartą ištirti atsakymo:

List<? extends A> List<? extends A> reiškia, kad ji priims bet kurį „ A ir „ A “ poklasį. Tačiau į šį sąrašą negalite pridėti nieko. Net ir A tipo objektai.

List<? super A> List<? super A> reiškia, kad jis priims bet kurį A sąrašą ir „ A “ klasės viršūnę A Galite pridėti A tipo objektus ir jų poklasius.

1
23 авг. atsakymas, kurį pateikė jforex78 23 rug . 2017-08-23 00:05 '17 - 0:05 2017-08-23 00:05

Dažniausios pakaitos simboliai skirti dviem pagrindiniams poreikiams:

Skaitymas iš bendrinamos kolekcijos Įterpimas į bendrąją kolekciją Yra trys būdai, kaip apibrėžti rinkinį (kintamąjį), naudojant įprastus vietinius simbolius. Tai yra:

 List<?> listUknown = new ArrayList<A>(); List<? extends A> listUknown = new ArrayList<A>(); List<? super A> listUknown = new ArrayList<A>(); 

List<?> Reiškia sąrašą, kuris įvedamas nežinomu tipu. Tai gali būti List<A> , List<B> , List<String> ir tt

List<? extends A> List<? extends A> reiškia objektų, kurie yra class A atvejai arba class A subclasses of A (pvz., B ir C), sąrašas. List<? super A> List<? super A> reiškia, kad sąrašas yra įvedamas A class arba A class

Sužinokite daugiau: http://tutorials.jenkov.com/java-generics/wildcards.html

1
23 авг. atsakymą pateikė Vaibhav Gupta 23 rug. 2015-08-23 16:25 '15 - 16:25 2015-08-23 16:25
  | v 

Sąrašas <? plečiasi X> ? gali būti bet kuris X arba X poklasis

Sąrašas <? super X> ? gali būti bet kuri X arba X klasė

  ^ | 
0
11 авг. atsakymas pateikiamas snr 11 rug. 2018-08-11 10:35 '18, 10:35 am 2018-08-11 10:35

Pavyzdžiui, paveldėjimo tvarka laikoma O> S> T> U> V

Naudojant raktinių žodžių plėtinius,

Ištikimas:

 List<? extends T> Object = new List<T>(); List<? extends T> Object = new List<U>(); List<? extends T> Object = new List<V>(); 

Klaidingas:

 List<? extends T> Object = new List<S>(); List<? extends T> Object = new List<O>(); 

Super raktinis žodis:

Ištikimas:

 List<? super T> Object = new List<T>(); List<? super T> Object = new List<S>(); List<? super T> Object = new List<O>(); 

Klaidingas:

 List<? super T> Object = new List<U>(); List<? super T> Object = new List<V>(); 

Objekto pridėjimas: sąrašo objektas = naujas sąrašas ();

 Object.add(new T()); //error 

Bet kodėl klaida? Pažvelkime į sąrašo objekto inicijavimo galimybes.

 List<? extends T> Object = new List<T>(); List<? extends T> Object = new List<U>(); List<? extends T> Object = new List<V>(); 

Jei mes naudojame Object.add (naujas T ()); tada jis bus teisingas tik tada, jei

 List<? extends T> Object = new List<T>(); 

Tačiau yra dar dvi galimybės.

Sąrašo objektas = naujas sąrašas (); Sąrašo objektas = naujas sąrašas (); Jei bandysime pridėti (naują T ()) aukščiau nurodytoms dviem galimybėms, tai suteiks klaidą, nes T yra aukščiausia U ir V klasė, mes bandome pridėti objektą T [kuris (naujas T ())] į U ir V tipų sąrašą. Aukštesnės klasės objektas (bazinė klasė) negali būti perkeliamas į žemesnę Objekto klasę (subklasę).

Dėl dviejų papildomų funkcijų „Java“ suteikia klaidą, net jei naudojate tinkamą funkciją, nes „Java“ nežino, kokio objekto turite. Taigi negalite pridėti objektų į sąrašo objektą = naują sąrašą (); nes yra galimybių, kurios yra negaliojančios.

Objekto pridėjimas: sąrašo objektas = naujas sąrašas ();

 Object.add(new T()); // compiles fine without error Object.add(new U()); // compiles fine without error Object.add(new V()); // compiles fine without error Object.add(new S()); // error Object.add(new O()); // error 

Bet kodėl klaida atsiranda ankstesniuose dviejuose? galime naudoti Object.add (naują T ()); tik su šiomis galimybėmis

 List<? super T> Object = new List<T>(); List<? super T> Object = new List<S>(); List<? super T> Object = new List<O>(); 

Jei bandėme naudoti Object.add (naujas T ()) sąraše Objektas = naujas sąrašas (); ir sąrašo objektas = naujas sąrašas (); tada jis duos klaidą. Taip yra dėl to, kad negalime pridėti objekto T [kuris yra naujas T ()] į sąrašo objektą = naują sąrašą (); nes jis yra U tipo objektas. Negalime pridėti objekto T [, kuris yra naujas T ()] U objekte, nes T yra bazinė klasė, o U - poklasis. Mes negalime pridėti bazinės klasės į poklasį ir kodėl įvyksta klaida. Tai taikoma ir kitam atvejui.

-1
22 июля '18 в 20:57 2018-07-22 20:57 atsakymas pateiktas Crox liepos 22 d., 18 val. 20:57 2018-07-22 20:57

Kiti klausimai apie „ ar Užduoti klausimą