Verständnisproblem bei Anwendung von Lower Bounded Wildcards

2b|!2b

Mitglied
Guten Morgen,
Ich beschäftige mich gerade mit generischen Klassen und speziel mit Wildcards.

Bei den lower Bounded Wildcards habe ich Probleme. Ich habe das so verstanden, dass wenn ich etwas mit <? super "BeispielKlasse"> typisiere, nur Objekte zuweisen kann, die in der Hierarchie höher oder gleich der Beispielklasse sind.

Habe um das Nachvollziehen zu können Klassen mit folgender Erbschaftsbeziehung erstellt:
Klamotten -> Hose -> Jeans
Dazu kommt noch eine generische Klasse "Behälter" mit zwei privaten Variablen, die eben zwei Objekte übergeben bekommen soll.

In der main habe ich nun zwei Jeans-Objekte instantiiert.
Wenn ich diese jetzt an ein Behaelter<? super Hosen>-Objekt im Konstruktor übergebe, dann müsste mir doch der Compiler die Jeansobjekte rot markieren oder nicht? Das tut er bei mir nämlich nicht. Ich kann das Programm ohne Probleme laufen lassen, egal welchen Objekttyp ich an den Konstruktor übergebe.
Code:
package test;

public class Probe{

   
    public static void main (String[] args) {
        Kleidung k0 = new Kleidung();
        Kleidung k1 = new Kleidung();
        Hose h0 = new Hose();
        Hose h1 = new Hose();
        Jeans j0 = new Jeans();
        Jeans j1 = new Jeans();
       
        //Behälter hat WildCard für alles was hierarchisch gleich und über Hose liegt
        //nachfolgender Code funktioniert aber trotzdem...?!
        Behaelter<? super Hose> behaelter = new Behaelter<>(j0,j1);
    }

}

Außerdem habe ich noch eine Frage zu der letzten Zeile im Code. Wenn ich schreibe:
Code:
        Behaelter<? super Hose> behälter = new Behaelter<? super Hose>(j0,j1);
dann meckert der Compiler folgendes: unexpected type. class or interface qithout bounds.

Was ist damit gemeint und warum muss ich die letzten Spitzklammern leer lassen, damit er nicht meckert?

Vielen Dank für eure Hilfe 🙂
 
Okay habs selbst rausbekommen 🙄

Wenn man die zweite Frage beantwortet, dann erklärt sich auch die Erste.

Die linken Spitzklammern beschreiben die eigentliche Lower Bounded Wildcard und in die rechten Spitzklammern können alle Typen hineingeschrieben werden, die in der Hierarchieebene über der unteren Grenze liegen (in diesem Fall Hose).

Erst dann funktioniert sozusagen auch die Wildcard-Funktion und er meckert wenn ich die Jeans-Objekte übergeben will.
 
ich würde mich über einen Erklärungsversuch schon freuen 😀 wenn ich nämlich folgendes mache:
Code:
        Behaelter<? super Hose> behälter = new Behaelter<>("1 ","e");
Meckert der Compiler nämlich nicht obwohl ich doch der Referenz "Behaelter<? super Hose>" verbiete ihm etwas anderes zu übergeben Objekte, die in der Klassenhierarchie über ihm stehen. Und Die Strings dürften ja nicht übergeben werden, oder nicht?
 
Also eigentlich geht es darum, was die Variable behälter sein kann.
Möglich ist genau das:
Java:
Behaelter<? super Hose> behälter = new Behaelter<Hose>();
Behaelter<? super Hose> behälter = new Behaelter<Kleidung>();
Behaelter<? super Hose> behälter = new Behaelter<Object>();
Man kann alles in den Behälter werfen, dass eine Hose oder in der Hierarchie darüber steht.
Es ist nun garantiert, dass man aus dem Behälter nur Object lesen kann, aus eben oben stehenden Gründe.

Beispiel:
Java:
public class Test {
  public static void main(String... args) {
    Kleidung k0 = new Kleidung();
    Kleidung k1 = new Kleidung();
    Hose h0 = new Hose();
    Hose h1 = new Hose();
    Jeans j0 = new Jeans();
    Jeans j1 = new Jeans();
 
    Behaelter<? super Hose> behaelter = new Behaelter<>(j0, j1, k0);
    for (Object object : behaelter) {
      System.out.println(object);
    }
  }
}
class Kleidung {
 
  @Override
  public String toString() {
    return "Kleidung []";
  }
}

class Hose extends Kleidung {
 
  @Override
  public String toString() {
    return "Hose []";
  }
 
}

class Jeans extends Hose {
 
  @Override
  public String toString() {
    return "Jeans []";
  }
 
}

class Behaelter<T> implements Iterable<T> {
  private Collection<T> coll;
 
  @SafeVarargs
  public Behaelter(T... ts) {
    coll = Arrays.asList(ts);
  }
 
  @Override
  public String toString() {
    return "Behaelter [coll=" + coll + "]";
  }
 
  @Override
  public Iterator<T> iterator() {
    return coll.iterator();
  }
 
}
Wenn du Strings übergibst, macht der Diamond genau das aus deinem Typ:
Java:
Behaelter<? super Hose> behaelter = new Behaelter<Object>("a", "b");
Und hier ist es absolut valide einen String zu übergeben, da er ein Object ist.
 
Zuletzt bearbeitet:
Ah! behaelter wird also meckern, wenn ich in den rechten Diamond folgendes Schreibe:
Code:
    Behaelter<? super Hose> behaelter = new Behaelter<Hose>(j0, j1, k1);
Das liegt daran, dass der durch behaelter referenzierte Collector dann nur noch Referenzen vom Typ Hose und Jeans aufnehmen kann. Die Referenz k1 vom typ Kleidung ist nicht mehr zulässig.

Wenn ich aber den rechten Diamond leer lasse kann ich hingegen alles da reintun, wass von Object erbt.

Vielen Dank für die Mühe!
 

Zurück
Oben