How to use List<? extends >? [duplicate] - java

This question already has answers here:
How can I add to List<? extends Number> data structures?
(7 answers)
Difference between <? super T> and <? extends T> in Java [duplicate]
(14 answers)
Closed 10 months ago.
I want to list.addAll, but get a error,
what should I do?
The code as follow
public class Animal {
private void speak(){
System.out.println("Animal");
}
protected void name(){
System.out.println("name");
}
}
public class Dog extends Animal{
public void test(){
super.name();
speak();
}
private void speak(){
System.out.println("dog");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.test();
List<? extends Animal> animals = new ArrayList<>();
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
//TODO this is error
animals.addAll(dogs);
}
}
the error as follow
Required type: Collection <? extends capture of ? extends Animal>.
Provided: List< Dog >.

Related

not able to add Animal object with wildcard super of Dog [duplicate]

This question already has answers here:
What is PECS (Producer Extends Consumer Super)?
(16 answers)
Closed 12 months ago.
Had seen many examples related to use of super wildcard. Majority of them are with Number and Integer classes. However for my understanding I was trying the below code:
package util;
import java.util.*;
class Animal{
void eat() {
System.out.println("animal eats");
}
}
class Dog extends Animal{
void eat() {
System.out.println("dog eats");
}
}
class Cat extends Animal{
void eat() {
System.out.println("cat eats");
}
}
public class Test {
public void addAnimal(List<? super Dog> list) {
list.add(new Animal());//******* getting error here
list.add(new Dog());
}
public static void main(String[] args) {
List<? super Dog> lsDogs = new ArrayList<Dog>();
List<? super Dog> lsAnimals = new ArrayList<Animal>();
}
}
as per the docs which I have understood super means we can add anything that is on right hand side or its super class. Here I created Dog class which extends Animal class. I can only add Dog type of objects and not Animal. Why is it not possible.. any specific reasons
List<? super Dog> says "this is a List that you can add a Dog to. You might be able to add a Dog because it is a List<Dog>, because it's a List<Animal>, or because it's a List<Object>."
You can't add an Animal to a List<? super Dog>, because your Animal could be any Animal subclass, e.g. a Cat, and then you may have a Cat in a List<Dog>.
class Animal { void sound() {}}
class Cat extends Animal {}
class Dog extends Animal {}
class Test {
public static void main(String[] args) {
List<Object> objects = new ArrayList<>();
List<Animal> animals = new ArrayList<>();
List<Dog> dogs = new ArrayList<>();
List<Cat> cats = new ArrayList<>();
add(objects);
add(animals);
add(dogs);
add(cats); // Error, must be a list we can add Dogs to
addAnimal(objects);
addAnimal(animals);
addAnimal(dogs); // Error, must be a list which can contain any Animal
useList(objects); // Error, must be a List of Animals
useList(animals);
useList(dogs);
useList(cats);
}
public static void add(List<? super Dog> list) {
list.add(new Dog());
}
public static void addAnimal(List<? super Animal> list) {
list.add(new Dog());
list.add(new Cat());
for (Animal a : list) { // error, ? can be Object
a.sound();
}
}
// If we're consuming items from the list we use extends
public static void useList(List<? extends Animal> list) {
list.add(new Animal()); // error, ? is a specific but unknown subclass of Animal
for (Animal a : list) {
a.sound();
}
}
}
The ? means that we don't know what the class is but it is a definite class.
? super of Dog means that ? is something that is a parent of dog. For your example you have { Object, Animal, Dog }. So your ? can be any of those 3 classes.
You can add to the list as long as what every you add can be cast to ?.
Can you add a Dog to the list? Yes because Dog can be cast to any Object, Animal, Dog.
Can you add an Animal to the list? No, because Animal cannot be cast to Dog.
Since Dog is the most specified it is the boundary that we compare against. You can add any Dog or class that extends Dog.

Why cannot write in covariance in Java? [duplicate]

This question already has answers here:
What is a difference between <? super E> and <? extends E>?
(10 answers)
Closed 4 years ago.
I have code like this:
class Scratch {
public static void main(String[] args) {
List<Cat> cats = new ArrayList<>();
List<? extends Animal> animals = cats;
animals.add(new Cat()); // compile error
Animal animal = animals.get(0);
}
}
class Animal {
}
class Cat extends Animal {
}
class Dog extends Animal {
}
Why cannot add a Cat instance to animals? Add Cat instance or Dog instance to animals, and read elements as animal is type safe. I know PECS (short for "Producer extends and Consumer super"), but I can't understand that why can't write in covariance and cant't read in contravariance in Java.
<? extends Animal> is not Cat, it can be any subclass ot Animal, for example:
List<? extends Animal> dogs = new ArrayList<Dog>();
dogs.add(new Cat()); // compile error
No matter what actually type <? extends Aminal> is, it can't add any subclass of Animal. Use List<Animal> instead of List<? extends Animal>.

Adding element to generic List via reflection in Java

I am trying to create a generic method for sub classes lists which add a new element no matter which of the sub class I choose.
for that matter I made an example that will be easy to understand.
There is A zoo container of giraffes and zebras lists. zebra and giraffe are both Animals. I needed to create a'mate' method that will be able to get List of homo gene type meaning list of giraffe or zebra(but not both), and the mate method will add another animal of the type to the existing list (without copying) if there are more than 2 animals in the list.
so to solve this I thought to used reflection since I can not initiate a generic type in java(it is not allowed in java- new T() is not allowed).
so I created an instance of the first element, and tried to add it to the list with animals.add(newAnimal);.. however the compiler complains about it with the following error:
Error: java: no suitable method found for add(Animal)
method java.util.Collection.add(capture#1 of ? extends Animal) is not applicable
(argument mismatch; Animal cannot be converted to capture#1 of ? extends Animal)
method java.util.List.add(capture#1 of ? extends Animal) is not applicable
(argument mismatch; Animal cannot be converted to capture#1 of ? extends Animal)
I solve it by getting the add method at run-time using again, reflection, and it is working(the line in comment), however I would like to know why the compiler does not allow me to use add for animal, because I could not find the answer myself.
The code:
class Animal implements Comparable<Animal>{
int numLegs;
#Override
public int compareTo(Animal o) {
return this.numLegs-o.numLegs;
}
}
class Giraffe extends Animal{
int neckLength;
}
class Zebra extends Animal{
int numOfStripes;
}
class Zoo{
List<Giraffe> giraffes=new ArrayList<Giraffe>();
List<Zebra> zebras=new ArrayList<Zebra>();
public void printMostAnimals(){
for(Animal a: getMostAnimals()){
System.out.println(a);
}
}
private List<? extends Animal> getMostAnimals() {
if(giraffes.size()>zebras.size())
return giraffes;
return zebras;
}
public void mate(List<? extends Animal>animals) throws IllegalAccessException, InstantiationException {
if(animals.size()>2){
Class<?> firstAnimalInstanceClass=animals.get(0).getClass();
Animal newAnimal=(Animal)firstAnimalInstanceClass.newInstance();
animals.add(newAnimal);
// animals.getClass().getDeclaredMethod("add",Object.class).invoke(animals,newAnimal);
System.out.println("new mate was added");
return;
}
System.out.println("no mate been added");
}
}
class App{
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Zoo z=new Zoo();
z.zebras.add(new Zebra());
z.zebras.add(new Zebra());
z.zebras.add(new Zebra());
z.mate(z.zebras);
System.out.println("new zebra been added?"+(z.zebras.size()>3));
}
}
Thanks,
Because somebody might write:
List<Giraffe> giraffes = new ArrayList<>();
List<? extends Animal> animals = giraffes;
animals.add(new Zebra());
for (Giraffe g : giraffes) { // but there is a Zebra in there!
g.eatLeavesFrom(tallTree); // Zebras can't do that!
}
To have type safety when mating, you could do:
class Animal<M extends Animal<M>> {
M mate;
}
class Giraffe extends Animal<Giraffe> {}
class Zebra extends Animal<Zebra> {}
which allows you to write:
<A extends Animal<A>> void matingSeason(List<A> animals) {
A x = null;
for (A a : animals) {
if (x != null) {
a.mate = x;
x.mate = a;
x = null;
} else {
x = a;
}
}
}
you cannot add anything other than null to List<? extends Animal>.
Ex:
void foo(List<? extends Animal> animals ){
animals.add(new Animal());// compiler error
}
let's assume for a minute it doesn't raise a compiler error and i call foo(new ArrayList<Dog>()), it will add Animal to a List of dogs. clearly that shouldn't be allowed and thus the above code won't compile.
if this didn't raise an error the whole point of generic compile time safety is gone.
You are not allowed to add an Animal "aa" to a List<Giraffe> because "aa" could be a Zebra.
When you declare a List<? extends Animal>, you tell the compiler that it is a a List<Giraffe>, a List<Zebra> or a List<Animal>. Since it could be a List<Giraffe>, we fall in the case above, which means that you cannot add an Animal.
If you remove the generic, it should work, because you tell the compiler that there could be anything in the list:
((List)animals).add(newAnimal);
However you loose all type safety.
Instead why not do it as follows:
class AnimalList<AnimalType extends Animal> extends List<AnimalType> {
void mate() {
Class<AnimalType> firstAnimalInstanceClass = animals.get(0).getClass();
AnimalType newAnimal = (AnimalType)firstAnimalInstanceClass.newInstance();
add(newAnimal);
}
}
In your Zoo, you would declare:
AnimalList<Zebra>
AnimalList<Giraffe>
and then call mate without arguments:
AnimalList<? extends Animal> list;
list.mate();

Difference between List <? extends interface> and List <interface> [duplicate]

This question already has answers here:
When do Java generics require <? extends T> instead of <T> and is there any downside of switching?
(7 answers)
Generics : List<? extends Animal> is same as List<Animal>?
(3 answers)
Closed 5 years ago.
I have this interface:
public interface IModel extends Serializable{
boolean isOnDb();
}
I have an Object that implements the interface IModel :
public class Media implements Serializable, IModel {
#Override
public boolean isOnDb() {
return isOnDb;
}
}
I want to create a List where I can put objects that implement the interface IModel. Something like this:
List<? extends IModel> list= new ArrayList<>();
Media media = new Media();
list.add(m);
the code above doesn't compile. But I have no error if I do :
List<IModel> list= new ArrayList<>();
Media media = new Media();
list.add(m);
What's the difference between List<? extends IModel> and List<IModel>?
Thank you in advance

Why second example compiles sucessfuly [duplicate]

This question already has answers here:
Difference between <? super T> and <? extends T> in Java [duplicate]
(14 answers)
Closed 6 years ago.
import java.util.*;
class Test
{
public static class Base
{
}
public static class Derived1
extends Base
{
}
public static class Derived2
extends Base
{
}
public static void main (String[] args)
{
//Example1.
List<? extends Base> e = new ArrayList<Base>();
e.add(new Derived1()); //this won't compile
//Example2.
List<? super Base> b = new ArrayList<Base>();
b.add(new Derived1()); //this compiles
}
}
List<? super Base> b can be assigned either a List<Base> or a List<Object>. A Derived1 instance can be added to both, so the b.add(new Derived1()) statement passes compilation.
On the other hand, List<? extends Base> e may be assigned a List<Derived2>, so the compiler doesn't allow to add a Derived1 instance to it.
See What is PECS (Producer Extends Consumer Super)?.
If you are adding something to a List<T>, then the list is a consumer of the thing you are adding. As such, the type of the list elements, T, must be the same as the thing you are trying to add or a supertype.

Categories