Je semble avoir un malentendu sur la différence entre <Foo>
et <? extends Foo>
. D'après ma compréhension, si nous avions
ArrayList<Foo> foos = new ArrayList<>();
Cela indique que des objets de type Foo
peuvent être ajoutés à cette liste de tableaux. Comme les sous-classes de Foo
sont également de type Foo
, elles peuvent également être ajoutées sans erreur, comme illustré par
ArrayList<Foo> foos = new ArrayList<>();
foos.add(new Foo());
foos.add(new Bar());
où Bar extends Foo
.
Maintenant, disons que j'avais défini foos
comme
ArrayList<? extends Foo> foos = new ArrayList<>();
Ma compréhension actuelle est que cela exprime some unknown type that extends Foo
. Je suppose que cela signifie que tous les objets qui sont une sous-classe de Foo
peuvent être ajoutés à cette liste; ce qui signifie qu'il n'y a pas de différence entre ArrayList<Foo>
et ArrayList<? extends Foo>
.
Pour tester cela, j'ai essayé d'écrire le code suivant
ArrayList<? extends Foo> subFoos = new ArrayList<>();
subFoos.add(new Foo());
subFoos.add(new Bar());
mais a été invité avec l'erreur de compilation suivante
no suitable method found for add(Foo)
method Java.util.Collection.add(capture#1 of ? extends Foo) is not applicable
(argument mismatch; Foo cannot be converted to capture#1 of ? extends Foo)
no suitable method found for add(Bar)
method Java.util.Collection.add(capture#2 of ? extends Bar) is not applicable
(argument mismatch; Bar cannot be converted to capture#2 of ? extends Bar)
D'après ma compréhension actuelle, je peux voir pourquoi je ne pourrais peut-être pas ajouter un Foo
à une liste de <? extends Foo>
, car ce n'est pas une sous-classe en soi; mais je suis curieux de savoir pourquoi je ne peux pas ajouter un Bar
à la liste.
Où est le trou dans ma compréhension?
Comme vous l'avez découvert par vous-même, un ArrayList
déclaré comme ArrayList<? extends Foo> subFoos = new ArrayList<>();
ne serait pas très utile.
Afin de voir l'utilité de <? extends T>
considère ceci:
List<Foo> collect( List<? extends Foo> a1, List<? extends Foo> a2 )
{
List<Foo> collected = new ArrayList<>();
collected.addAll( a1 );
collected.addAll( a2 );
return collected;
}
qui peut ensuite être utilisé comme suit:
List<Foo> foos = collect( new ArrayList<Foo>(), new ArrayList<Bar>() );
ou comme suit:
List<Foo> foos = collect( new ArrayList<Bar>(), new ArrayList<Foo>() );
notez que rien de ce qui précède n'aurait fonctionné si la méthode collect
avait été déclarée comme suit:
List<Foo> collect( List<Foo> a1, List<Foo> a2 )