Was versteht man unter Java Generics unter PECS (Producer extends consumer super)?

2 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Ich schätze mal, das könnte im Folgenden nun etwas länger werden. Hoffentlich kann ich es auch verständlich / einfach genug vermitteln.

Im Grunde geht es hierbei darum zu unterscheiden, wann man bei generischen Klassen extends oder super verwendet / wann es Sinn ergibt. Dazu betrachtet man die generische Klasse als Kollektion (sie nimmt ja ein Objekt bestimmten Typs in sich auf).

Producer extends

Wenn du lediglich Elemente aus der Kollektion herausziehst, handelt es sich um einen Producer. Die Kollektion produziert/gibt Objekte bestimmten Typs.

Ein typischer Anwendungsfall wäre das Durchlaufen einer Liste an Objekten, auf denen jeweils irgendeine Operation ausgeführt werden soll, über die sie alle verfügen:

class Vehicle {
  public void drive() {
    System.out.println("");
  }
}
           
class Car extends Vehicle {
  @Override
  public void drive() {
    System.out.println("Broam broam.");
  }
}

// main:
ArrayList<Car> cars = new ArrayList<>();
cars.add(new Car());
 
List<? extends Vehicle> vehiclesInGarage = cars;
 
for (Vehicle vehicle : vehiclesInGarage) {
  vehicle.drive(); // output: Broam broam.
} 

In diesem Beispiel wird sichergestellt, dass eine Liste nur Objekte enthält, die von einem bestimmten Basistyp (Vehicle) abstammen. Das Schlüsselwort extends ermöglicht diese Einschränkung.

Hinzufügen kannst du aber keine Elemente:

vehiclesInGarage.add(new Vehicle()); // does not work

da nicht bestimmt ist, welchen Subtyp die Kollektion zur Laufzeit nun wirklich in sich hält. In diesem Fall sind es konkret Objekte des Subtyps Car, doch genauso könnte es eine Liste an Vehicles oder weiterer Subtypen sein. Dies kann vom Computer erst zur Laufzeit wieder ermittelt werden.

Consumer super

Wenn du lediglich Elemente in die Kollektion hineinstopfst, handelt es sich um einen Consumer. Die Kollektion bezieht Objekte bestimmten Typs. Das Schlüsselwort super kann für den generischen Typ angewandt werden.

Ein Beispiel:

class Vehicle {
  public void drive() {
    System.out.println("");
  }
}
           
class Car extends Vehicle {
  @Override
  public void drive() {
    System.out.println("Broam broam.");
  }
}
 
class ElectronicCar extends Car {
   public void drive() {
      www.em.out.println("Zwwrrrzwwww.");
   }
}

// main:
ArrayList<Car> cars = new ArrayList<>();
cars.add(new Car());

List<? super Car> carsInGarage = cars;
carsInGarage.add(new ElectronicCar());
carsInGarage.add(new Car());
carsInGarage.add(new Vehicle()); // does not work

Es ist möglich, Objekte in die Liste einzufügen, die mindestens die Basisklasse Car haben (oder halt die Basisklasse selbst).

Der dritte Fall:

Wenn beide Fälle zutreffen, solltest du keine zusätzliche Spezifizierung des generischen Typs vornehmen.


regex9  22.07.2018, 20:00

Irgendetwas hat meine ElectronicCar-Klasse zerrissen... sie sollte so aussehen:

class ElectronicCar extends Car {
  @Override
   public void drive() {
      System.out.println("Zwwwwwr.");
   }
}
0

Ohne Code kann damit niemand was anfangen. Das ist wie, als du jemandem eine Nachricht schreiben willst, aber nicht weißt wer der Empfänger ist und was der Inhalt der Nachricht sein soll.

Das keyword extends kennzeichnet in Java Vererbung. Die Klasse Producer erbt von Consumer, mehr ist da nicht zu erkennen keine Spur von Generics.


regex9  22.07.2018, 19:57

PECS ist eine Merkregel, wann man welchen generischen Wildcard verwendet.

0