Java Wildcards WildCard Pergunta: Listar

Digamos que eu tenha estas classs: Veículo, Carro e Nave Espacial:

class Vehicle{ void rideVehicle(Vehicle v){ System.out.println("I am riding a vehicle!"); } } class Car extends Vehicle{ void rideVehicle(Vehicle c){ System.out.println("I am riding a car!"); } } class SpaceShip extends Vehicle{ void rideVehicle(Vehicle c){ System.out.println("I am riding a spaceship!"); } } 

e eu escrevo este método addCars:

 private static void addCars(List vcls){ vcls.add(new Car()); vcls.add(new Car()); vcls.add(new Car()); } 

Por que recebo um erro de compilation? Eu entendo que List é um supertipo de List para qualquer X que estenda o Vehicle. certo?

obrigado

Edit: o erro que recebo (tempo de compilation): O método add (captura # 2 – de? Estende Vehicle) no tipo List não é aplicável para os argumentos (Car).

Os argumentos do método são contravariantes no subtipo, e pela definição do caractere curinga, para cada tipo T que estende o Vehicle Foo é um subtipo de Foo< * extends Vehicle> . A implicação disso é que os curingas são ótimos quando você se importa apenas com o tipo de retorno, mas não trabalha em situações como essa quando deseja passar um valor do tipo para um método.

O problema é que um usuário pode tentar ligar

 List l = ... addCars(l); 

se seu código fosse compilar, l seria uma lista de naves espaciais contendo 3 carros. Claramente não é bom.

Aqui está um ponteiro para porque você está recebendo um erro de compilation. Especificamente,

List é um exemplo de um curinga delimitado. O ? representa um tipo desconhecido, assim como os curingas que vimos anteriormente. No entanto, nesse caso, sabemos que esse tipo desconhecido é, na verdade, um subtipo de Shape. (Nota: Poderia ser a própria Forma, ou alguma subclass; ela não precisa literalmente estender a Forma.) Dizemos que a Forma é o limite superior do curinga.

Como sempre, há um preço a ser pago pela flexibilidade de usar curingas. Esse preço é que agora é ilegal escrever em formas no corpo do método. Por exemplo, isso não é permitido:

 public void addRectangle(List< ? extends Shape> shapes) { shapes.add(0, new Rectangle()); // Compile-time error! } 

Você deve ser capaz de descobrir por que o código acima não é permitido. O tipo do segundo parâmetro para shapes.add () é? estende Shape– um subtipo desconhecido de Shape. Como não sabemos de que tipo é, não sabemos se é um supertipo de Retângulo; pode ou não ser um supertipo, por isso não é seguro passar um retângulo por lá.

A Lista fornecida é uma lista de algum tipo específico de Veículo (onde, por uma questão de argumento, nos referiremos ao tipo como T ), mas esse tipo específico T não é conhecido; pode ser List , List , etc. Portanto, como o tipo genérico específico da lista é desconhecido, não é permitido chamar qualquer método que requeira o T específico como um argumento. Somente methods que não envolvem T como argumento podem ser invocados.

O resultado prático disso, no caso de List, é que isso impede que qualquer coisa seja adicionada à lista – a lista não é gravável. Por outro lado, a lista pode ser lida, mas com os objects retornados conhecidos apenas como Vehicle .

Ou seja, o tipo desconhecido T não pode ser fornecido para a Lista, mas sua superclass conhecida de Vehicle pode ser retornada pela lista.

Por exemplo, dado seu método:

 private static void addCars(List< ? extends Vehicle> vcls) { 

você poderia invocar:

 List cars=new ArrayList(); addCars(cars); 

que você intui deve ser permitido. No entanto, como o addCars conhece a lista apenas como “algum subtipo de Vehicle “, não é permitido adicionar objects à lista, pois a chamada a seguir seria válida:

 List ships=new ArrayList(); addCars(ships); 

em que se torna claro que deve ser um erro tentar adicionar objects Car a uma lista, sob o pretexto de ser uma lista de objects Vehicle .

 private static void addCars(List< ? extends Vehicle> vcls){ 

deveria estar

 private static void addCars(List< ? super Vehicle> vcls){ 

Isso irá corrigir o erro de tempo de compilation.

EDIT: leia aqui .

O tipo de parâmetro é ? extends Vehicle ? extends Vehicle , o que significa um subtipo desconhecido de Vehicle . Como não sabemos de que tipo é, não sabemos se é um supertipo de Car ; pode ou não ser um supertipo, por isso não é seguro passar um Car lá.

Leia a página 7 deste tutorial .

Quando você diz < ? extends Vehicle> < ? extends Vehicle> significa que pode ser de qualquer tipo que estenda o veículo. Isso significa que alguém pode passar List e aceitará. Agora uma List não pode ter o novo Car () como um de seus itens. Portanto, para evitar esses erros, você não tem permissão para adicionar nenhum object dentro da lista se tiver usado a expressão curinga.

Você pode usar:

 private static void addCars(List< ? super Vehicle> vcls) 

(o que significa que o chamador deve passar uma lista de objects que são Veículo ou um tipo super)

ou

 private static void addCars(List vcls) 

se seguir seria possível ..

 private static void addCars(List< ? extends Vehicle> vcls){ vcls.add(new Car()); vcls.add(new Car()); vcls.add(new Car()); } 

então você poderia chamar addCars desta maneira:

 List ships = new ArrayList(); addCars(ships); 

O Problema do Princípio Get and Put:

você pode tentar isso

 private static void addCars(List< ? super Car> vcls){ vcls.add(new Car()); vcls.add(new Car()); vcls.add(new Car()); 

é como;

List ints=Arrays.asList(1,2,3); List< ? extends Number> nums=ints; double dbl=sum(nums); // ===ok nums.add(3.14); //===compile-time-error

e para curinga para Listints=Arrays.asList(1,"two"); List< ? super Integer> nums=ints; double dbl=sum(nums); // ===compile-time-error nums.add(3.14); //===ok Listints=Arrays.asList(1,"two"); List< ? super Integer> nums=ints; double dbl=sum(nums); // ===compile-time-error nums.add(3.14); //===ok

Usando prince get e colocar em curinga Se curinga com Extends —> Usando o método get Se o curinga com Super —-> Usando o método put Aqui, você deseja adicionar valor em Lista (o que significa put method) .Você pode alterar o código

 List< ? extends Vehicle become List then it will compile legally private static void addCars(List< ? super Vehicle> vcls){ vcls.add(new Car()); vcls.add(new Car()); vcls.add(new Car()); }