Java >> Java tutorial >  >> Tag >> extends

Forskellen mellem <? super T> og <? udvider T> i Java

extends

Wildcard-erklæringen List<? extends Number> foo3 betyder, at nogen af ​​disse er juridiske opgaver:

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
  1. Læser - Givet ovenstående mulige tildelinger, hvilken type objekt er du garanteret at læse fra List foo3 :

    • Du kan læse en Number fordi enhver af de lister, der kunne tildeles til foo3 indeholde en Number eller en underklasse af Number .
    • Du kan ikke læse en Integer fordi foo3 kunne pege på en List<Double> .
    • Du kan ikke læse en Double fordi foo3 kunne pege på en List<Integer> .
  2. Skrivning - Givet ovenstående mulige tildelinger, hvilken type objekt kunne du tilføje til List foo3 det ville være lovligt for alle ovenstående mulige ArrayList opgaver:

    • Du kan ikke tilføje en Integer fordi foo3 kunne pege på en List<Double> .
    • Du kan ikke tilføje en Double fordi foo3 kunne pege på en List<Integer> .
    • Du kan ikke tilføje en Number fordi foo3 kunne pege på en List<Integer> .

Du kan ikke tilføje noget objekt til List<? extends T> fordi du ikke kan garantere, hvilken slags List det peger virkelig på, så du kan ikke garantere, at objektet er tilladt i den List . Den eneste "garanti" er, at du kun kan læse fra den, og du får en T eller underklasse af T .

super

Overvej nu List <? super T> .

Wildcard-erklæringen for List<? super Integer> foo3 betyder, at nogen af ​​disse er juridiske opgaver:

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
  1. Læser - Givet ovenstående mulige tildelinger, hvilken type objekt er du garanteret at modtage, når du læser fra List foo3 :

    • Du er ikke garanteret en Integer fordi foo3 kunne pege på en List<Number> eller List<Object> .
    • Du er ikke garanteret en Number fordi foo3 kunne pege på en List<Object> .
    • Den eneste garanti er, at du får en forekomst af en Object eller underklasse af Object (men du ved ikke hvilken underklasse).
  2. Skrivning - Givet ovenstående mulige tildelinger, hvilken type objekt kunne du tilføje til List foo3 det ville være lovligt for alle ovenstående mulige ArrayList opgaver:

    • Du kan tilføje en Integer fordi en Integer er tilladt i enhver af ovenstående lister.
    • Du kan tilføje en forekomst af en underklasse af Integer fordi en forekomst af en underklasse af Integer er tilladt i enhver af ovenstående lister.
    • Du kan ikke tilføje en Double fordi foo3 kunne pege på en ArrayList<Integer> .
    • Du kan ikke tilføje en Number fordi foo3 kunne pege på en ArrayList<Integer> .
    • Du kan ikke tilføje en Object fordi foo3 kunne pege på en ArrayList<Integer> .

PECS

Husk PECS :"Producer udvider, forbruger Super" .

  • "Producer udvider" - Hvis du har brug for en List at producere T værdier (du vil læse T s fra listen), skal du angive det med ? extends T , for eksempel. List<? extends Integer> . Men du kan ikke tilføje til denne liste.

  • "Forbruger Super" - Hvis du har brug for en List at forbruge T værdier (du vil skrive T s på listen), skal du erklære den med ? super T , for eksempel. List<? super Integer> . Men der er ingen garantier for, hvilken type objekt du kan læse fra denne liste.

  • Hvis du både skal læse fra og skrive til en liste, skal du deklarere den nøjagtigt uden jokertegn, f.eks. List<Integer> .

Eksempel

Bemærk dette eksempel fra Java Generics FAQ. Bemærk hvordan kildelisten src (producerende listen) bruger extends og destinationslisten dest (den forbrugende liste) bruger 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)); 
  } 
}

Se også Hvordan kan jeg tilføje til List datastrukturer?


Forestil dig at have dette hierarki

1. Forlænger

Ved at skrive

    List<? extends C2> list;

du siger det list vil være i stand til at referere til et objekt af typen (for eksempel) ArrayList hvis generiske type er en af ​​de 7 undertyper af C2 (C2 inkluderet):

  1. C2: new ArrayList<C2>(); , (et objekt, der kan gemme C2 eller undertyper) eller
  2. D1: new ArrayList<D1>(); , (et objekt, der kan gemme D1 eller undertyper) eller
  3. D2: new ArrayList<D2>(); , (et objekt, der kan gemme D2 eller undertyper) eller...

og så videre. Syv forskellige tilfælde:

    1) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
    2) new ArrayList<D1>(): can store    D1    E1 E2  
    3) new ArrayList<D2>(): can store       D2       E3 E4
    4) new ArrayList<E1>(): can store          E1             
    5) new ArrayList<E2>(): can store             E2             
    6) new ArrayList<E3>(): can store                E3             
    7) new ArrayList<E4>(): can store                   E4             

Vi har et sæt "opbevarbare" typer for hver mulig sag:7 (røde) sæt her grafisk repræsenteret

Som du kan se, er der ikke en sikker type der er fælles for alle tilfælde:

  • du kan ikke list.add(new C2(){}); fordi det kunne være list = new ArrayList<D1>();
  • du kan ikke list.add(new D1(){}); fordi det kunne være list = new ArrayList<D2>();

og så videre.

2. Super

Ved at skrive

    List<? super C2> list;

du siger det list vil være i stand til at referere til et objekt af typen (for eksempel) ArrayList hvis generiske type er en af ​​de 7 supertyper af C2 (C2 inkluderet):

  • A1: new ArrayList<A1>(); , (et objekt, der kan gemme A1 eller undertyper) eller
  • A2: new ArrayList<A2>(); , (et objekt, der kan gemme A2 eller undertyper) eller
  • A3: new ArrayList<A3>(); , (et objekt, der kan gemme A3 eller undertyper) eller...

og så videre. Syv forskellige tilfælde:

    1) new ArrayList<A1>(): can store A1          B1 B2       C1 C2    D1 D2 E1 E2 E3 E4
    2) new ArrayList<A2>(): can store    A2          B2       C1 C2    D1 D2 E1 E2 E3 E4
    3) new ArrayList<A3>(): can store       A3          B3       C2 C3 D1 D2 E1 E2 E3 E4
    4) new ArrayList<A4>(): can store          A4       B3 B4    C2 C3 D1 D2 E1 E2 E3 E4
    5) new ArrayList<B2>(): can store                B2       C1 C2    D1 D2 E1 E2 E3 E4
    6) new ArrayList<B3>(): can store                   B3       C2 C3 D1 D2 E1 E2 E3 E4
    7) new ArrayList<C2>(): can store                            C2    D1 D2 E1 E2 E3 E4

Vi har et sæt "opbevarbare" typer for hver mulig sag:7 (røde) sæt her grafisk repræsenteret

Som du kan se, har vi her syv sikre typer der er fælles for alle sager:C2 , D1 , D2 , E1 , E2 , E3 , E4 .

  • du kan list.add(new C2(){}); fordi, uanset hvilken type liste vi refererer til, C2 er tilladt
  • du kan list.add(new D1(){}); fordi, uanset hvilken type liste vi refererer til, D1 er tilladt

og så videre. Du har sikkert bemærket, at disse typer svarer til hierarkiet startende fra type C2 .

Bemærkninger

Her er det komplette hierarki, hvis du ønsker at lave nogle tests

interface A1{}
interface A2{}
interface A3{}
interface A4{}

interface B1 extends A1{}
interface B2 extends A1,A2{}
interface B3 extends A3,A4{}
interface B4 extends A4{}

interface C1 extends B2{}
interface C2 extends B2,B3{}
interface C3 extends B3{}

interface D1 extends C1,C2{}
interface D2 extends C2{}

interface E1 extends D1{}
interface E2 extends D1{}
interface E3 extends D2{}
interface E4 extends D2{}

Jeg elsker svaret fra @Bert F, men det er sådan, min hjerne ser det.

Jeg har et X i hånden. Hvis jeg vil skrive mit X ind i en liste, den liste skal enten være en liste over X eller en liste over ting, som min X kan opgraderes til, når jeg skriver dem i dvs. en hvilken som helst superklasse af X...

List<? super   X>

Hvis jeg får en liste, og jeg vil læse et X ud af den liste, det er bedre at være en liste over X eller en liste over ting, der kan sendes til X, når jeg læser dem op, dvs. alt, der udvider X

List<? extends X>

Håber dette hjælper.


Java tag