3

I got a problem ,eg :

Fruit Class

public class Fruit extends Food {

    public static void main(String[] args) {
        Plate<? super Fruit> plate = new Plate<>(new Food());
        plate.setItem(new Apple());
        plate.setItem(new Food());
    }


    static class Apple extends Fruit {

    }
}

Food Class

public class Food {
}

Plate Class'

public class Plate<T> {

    private T item;

    public Plate(T t) {
        item = t;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}

I don't understand why

Plate<? super Fruit> plate = new Plate<>(new Food())

not error

but

plate.setItem(new Food()) 

is error

What is the difference between these two methods?

-that all, thanks!

Shivam Kumar
  • 1,892
  • 2
  • 21
  • 33
ciampion
  • 33
  • 3
  • 1
    `Plate super Fruit>` should be read as "a Plate that it is known to be safe to add a Fruit to". It doesn't mean it's *not* safe to add Food to it; merely that the compiler can't prove that it will be. – Andy Turner Feb 27 '19 at 07:48

2 Answers2

1

There are two things happening on this line:

Plate<? super Fruit> plate = new Plate<>(new Food());

new Plate<>(new Foo()) creates a new instance of Plate. The generic parameter here is inferred to be Food, so the right hand side creates a Plate<Food> object.

The second thing is that this object is assigned to plate. plate can be a Plate<T> as long as T is Fruit or a super class of Fruit. Is Food a superclass of Fruit? Yes, so the right hand side can be assigned to plate.

On this line however:

plate.setItem(new Food()) 

You are setting a plate's item. That plate could be a plate of anything, as long as it is Fruit or a superclass of Fruit. This means that passing a Food object wouldn't work. Why? Well, what if plate is actually a Plate<Fruit>? It could be, couldn't it? The compiler doesn't know.

So the only thing you can pass to plate.setItem are Fruit and subclasses of Fruit.

Nicholas K
  • 15,148
  • 7
  • 31
  • 57
Sweeper
  • 213,210
  • 22
  • 193
  • 313
1

It is a classical case of PECS.

When using super here, you created something that can get consumed but not produce anything to it of the type specified. This is exactly what you were trying to do.

To simplify it a bit, here is an example of what you could do with your object.

Plate<? super Fruit> plate = new Plate<>(...);
Fruit fruit = plate.getItem(); // GOOD !
Food food = plate.getItem(); // GOOD ! Because even a Fruit can be assigned to a Food reference so it's OK !
Apple apple = plate.getItem(); // BAD ! No insurance it is an apple, we just know it is a Fruit

plate.setItem(new Fruit()); // GOOD !
plate.setItem(new Apple()); // GOOD ! Because we know it's always a Fruit, and Apple extends Fruit
plate.setItem(new Food()); // BAD ! No insurance we're not dealing with a Fruit, and a Food object can't be assigned to a Fruit reference (without casting)
Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89