Collections Queue<? extends Number> add() offer()

tsitra

Bekanntes Mitglied
Hallo,

bei der Erkundung de Themas "generics" bzw. generische Collections
bin ich auf folgendes gestoßen was ich einfach nicht einordnen kann

Java:
 Queue<? extends Number> q1 = null;
         boolean boo1 = q1.offer(new Integer(88));  // C-FM capture ...  
         boolean boo2 = q1.add(new Integer(99));   // C-FM  cannot find symbol

Warum bekomme ich hier die Fehlermeldungen vom Compiler?

Für mich bedeutet Queue<? extends Number> q1 = null; dass in q1
Integer-Objekte hinzugefügt werden können, weil ...Integer extends Number... also "Integer IS-A Number"
Der "upper bound" ist hier "Number" aber Number-Objekte gehen nicht, weil es die garnicht, weil abstract, gibt.

Wer kennt sich hier aus und kann mir einen Hinweis geben?

Viele Grüße
vom Rhein

tsitra
 

Marco13

Top Contributor
Das hat damit nichts zu tun. Die Methoden sollten beide nicht gehen.

Der Grund, weswegen sie nicht gehen, ist im ersten Moment etwas ... subtil. Aber stell' dir folgendes vor
Java:
        class SomeClass
        {
            private Queue<Float> queue;

            public Queue<? extends Number> getQueue() 
            { 
                // Geht: Das ist eine Queue, die etwas enthält, was "Number" extendet
                return queue; 
            }

            public void readQueue()
            {
                Float f = queue.peek();
            }

        }
Und jetzt macht jemand
Java:
Queue<? extends Number> q = someClass.getQueue(); // Passt, siehe oben
q.add(new Integer(123)); // Sollte deiner Meinung nach gehen...
q.readQueue(); // Versucht, einen Float zu lesen - *knirsch*

Bei der Frage: "Warum erlaubt er mit die-und-jene Operation mit Generics nicht?" ist die Antwort praktisch immer: "Weil dann in irgendeiner Weise die Typsicherheit verloren gehen könnte".
 

fastjack

Top Contributor
Das ist eigentlich etwas anders:

Bei der Verwendung von (? extends T) ist der Zugriff auf das tatsächliche Object hinter (T) eingeschränkt. Du kannst keine Methoden aufrufen, die den Typen (T) als Parameter hätten. Beispiel add(), offer() usw.
Verwendest Du stattdessen (? super T) hast Du auch Einschränkungen, aber nur in Bezug auf Methoden, die als Returntyp (T) haben.

Java:
        Queue<? extends Number> q1 = new ArrayDeque<Number>();
        boolean boo1 = q1.offer(new Integer(4711)); // geht nicht
        boolean boo2 = q1.add(new Integer(99)); // geht nicht
        Number n = q1.peek(); // geht

Java:
        Queue<? super Number> q1 = new ArrayDeque<Number>();
        boolean boo1 = q1.offer(new Integer(4711)); // geht
        boolean boo2 = q1.add(new Integer(99)); // geht
        Number n = q1.peek(); // geht nicht
 

Landei

Top Contributor
Das Thema sind Generics, genauer gesagt Varianzen.

Invarianz

Wenn ich eine Variable vom Typ [c]List<Number>[c] habe, kann ich beliebige Unterklassen von Number hineinstopfen, und (als Number) wieder herausholen. Einer Variablen dieses Typs kann ich aber auch nur Sachen wie [c]ArrayList<Number>[/c], aber nicht [c]ArrayList<Float>[/c] zuweisen.

Kovarianz

Wenn ich eine Variable vom Typ [c]List<? extends Number>[/c] habe, heißt das, dass das "in Wirklichkeit" eine [c]List<Float>[/c] oder [c]List<Integer>[/c] oder so sein kann, ich den genauen Typ aber nicht weiß. Ich kann deshalb der Variablen z.B. eine [c]ArrayList<Double>[/c] zuweisen, das würde passen. Wenn ich etwas aus der Liste heraushohle, weiß ich, dass es sich um irgendeinen Untertyp von Number handeln muss, deshalb bekomme ich also Werte (als Number) aus der Liste heraus. Was nicht geht, ist etwas in die Liste hineinzustecken, eben weil ich den "wirklichen" Typ nicht kenne, also wie in Marcos Beispiel ein Integer in eine Float-Liste stopfen würde, weshalb das (bis auf den Wert null) nicht erlaubt ist.

Kontravarianz

... ist das Gegenteil von Kovarianz. Die Variable wird als [c]List<? super Number>[/c] definiert, und wir wissen nur, dass er "echte" Typ Number oder eine Oberklasse von Number (kann hier natürlich nur noch Object sein). Hineinstopfen eines Untertyps von Number ist erlaubt (das ist kein Problem, wenn die Liste Numbers oder Objects enthält), herausholen dagegen ist verboten, weil man "nicht weiß, was rauskommt".

Kurz gesagt hat Kovarianz den Effekt, eine Collection "read-only" zu machen, und Kontravarianz führt zu "write-only".

Kovarianz ist viel verbreiteter, aber auch Kontravarianz ist oft nützlich. Wenn ich z.B. eine Liste von Floats mit einem eigenen Comparator sortieren will, könnte man dafür nicht nur einen [c]Comparator<Float>[/c] verwenden, sondern auch ein [c]Comparator<Number>[/c] oder sogar ein [c]Comparator<Object>[/c] würde ausreichen, weshalb die entsprechende Methode [c]Collections.sort[/c] auch einen kontravarianten [c]Comparator<? super T>[/c] verlangt.

Beide Konzepte treten aber auch an anderer Stelle (die mit Generics nichts zu tun haben) auf. Z.B. darf ich eine Methode der Oberklasse, die Number zurückliefert, in der Unterklasse mit einer Version überschreiben, die die gleichen Argumente hat, aber Float zurückliefert ("covariant return type").
 
Zuletzt bearbeitet:

Andi_CH

Top Contributor
Das ist eigentlich etwas anders:

Bei der Verwendung von (? extends T) ist der Zugriff auf das tatsächliche Object hinter (T) eingeschränkt. Du kannst keine Methoden aufrufen, die den Typen (T) als Parameter hätten. Beispiel add(), offer() usw.
Verwendest Du stattdessen (? super T) hast Du auch Einschränkungen, aber nur in Bezug auf Methoden, die als Returntyp (T) haben.

Java:
        Queue<? extends Number> q1 = new ArrayDeque<Number>();
        boolean boo1 = q1.offer(new Integer(4711)); // geht nicht
        boolean boo2 = q1.add(new Integer(99)); // geht nicht
        Number n = q1.peek(); // geht

Java:
        Queue<? super Number> q1 = new ArrayDeque<Number>();
        boolean boo1 = q1.offer(new Integer(4711)); // geht
        boolean boo2 = q1.add(new Integer(99)); // geht
        Number n = q1.peek(); // geht nicht

Ich muss etwas verpasst haben - wenn ich das lese heisst das, dass ich

- im ersten Fall zwar etwas herausholen aber nichts hineinschreiben kann - äh - was soll ich denn rauskommen wenn nichts drin ist?

- im zweiten Fall etwas hineinschreiben, aber nichts herausholen kann (das ist ein WOM :) Write only memory = schwarzes Loch)

Wo ist meine Denkblockade?
 

fastjack

Top Contributor
Das hat doch Landei ausführlich erklärt:

List<? extends Number> -> read-only -> in dem ersten Beispiel gehen add() und offer() nicht, sondern nur peek()

List<? super Number> -> write-only -> in dem zweiten Beispiel gehen add() und offer() aber peek() eben nicht.
 
Zuletzt bearbeitet:

Andi_CH

Top Contributor
Muss ich wirklich noch betonen, dass das Ganze echt sinnlos währe wenn es so währe wie ich es im Moment wahrnehme?

Also meine Frage ausführlich umschrieben, dass auch die es verstehen die nicht von selbst drauf kommen was ich eigentlich fragen wollte:

"Wie setze ich das sinnvoll ein?"

Es macht doch wirklich keinen Sinn wenn ich q1 und q2 haben und aus q1 nur lesen und in q2 nur schreiben kann?

Java:
	Queue<? extends Number> q1 = new LinkedList<Integer>();
	Queue<? super Number> q2 = new ArrayDeque<Number>();

Ist jetzt alles klar oder muss ich noch detaillierter fragen? :bahnhof:
 
Zuletzt bearbeitet:
S

SlaterB

Gast
Java:
public class Test {
    public static void main(String[] args)  {
        List<Double> d = new ArrayList<Double>();
        d.add(4.2);
        List<Integer> i = new ArrayList<Integer>();
        i.add(4);
        check(d);
        check(i);
    }

    static void check(List<? extends Number> list) {
        Number n = list.get(0); // erlaubt und sinnvoll
        if (n.doubleValue() < 4.1)  {
            System.out.println("toll");
        }
        list.add(3); // zum Glück verboten
    }
}
 

Marco13

Top Contributor
Ne, ich glaub' es ist schon klar. Das "Problem" dabei ist, dass die Liste an einer Stelle "genauer" bekannt ist, und an anderer weniger genau.
Java:
List<Float> floatList = new ArrayList<Float>();
List<? extends Number> numberList = floatList; // Geht

floatList.add(new Float(123)); // Geht
numberList.add(new Float(123)); // Geht nicht

Number n0 = floatList.get(0); // Geht
Float f0 = floatList.get(0); // Geht

Number n1 = numberList.get(0); // Geht 
Float f1 = numberList.get(0); // Geht nicht

Das Beispiel oben mit der "SomeClass" war schon bewußt gewählt: Oft hat man "intern" eine Liste, von der man weiß, was drin ist, aber man will diese (ggf. implementierungsspezifische) Information nicht nach draußen geben. Etwas "realistischer" wäre vielleicht
Java:
class SomeClass
{
    private List<VerySpecialMouseListener> listeners = ...

    public List<? extends MouseListener> getListeners() { return listeners; }
}
Die Klasse verwaltet ihre eigenen, "VerySpecial" MouseListeners. Nach draußen gibt sie aber nur eine Liste mit "irgendwelchen" MouseListenern. (Das hat dann eben nebenbei zur Folge, dass in diese Liste niemand irgendeinen "falschen" MouseListener reinlegen kann)


EDIT: Da war ich etwas zu langsam. Aber nochmal spezifisch auf SlaterB's Beispiel bezogen: Das Konstrukt mit "? extends T" verwendet man, um eine API (im Sinne von Funktionen, die man anbietet) flexibler zu machen in bezug auf die Dinge, die man "annimmt". Es erweitert die möglichen Parameter für eine Methode, analog (oder kovariant ;) ) zum "Programmieren gegen das Interface":
Java:
void check(ArrayList<Integer> list) { ... } // Nur ArrayListen mit Integern
void check(List<Integer> list) { ... } // Besser: Beliebige Listen mit Integern
void check(List<Number> list) { ... } // Listen mit Zahlen - funktioniert nicht für ArrayList<Integer> !!!
void check(List<? extends Number> list) { ... } // Listen mit Zahlen
Die letzte Methode funtkioniert mit ArrayList<Integer> genauso wie mit LinkedList<Float>. Natürlich nur solange in der Methode die liste nicht mit Zahlen gefüllt werden muss, weil man DA eben dann wegen "? extends Number" nicht wüßte, ob man nun Integers oder Float reinpacken darf...
 
Zuletzt bearbeitet:

Landei

Top Contributor
Schöne Erklärung von Marco. Ergänzend sei angemerkt, dass man mit Varianzen auch seinen eigenen Code so "allgemein" wie möglich formulieren kann. Ein Beispiel:

Java:
 public static <C extends Comparable<? super C>> C maximum(List<? extends C> list) {
        C c = list.isEmpty() ? null : list.get(0);
        for(C d : list) if (c.compareTo(d) < 0) c = d;
        return c;
}

Dieser Code macht wirklich nur die allernötigsten Annahme darüber, welche Eigenschaften die Liste haben muss. Damit kommt er selbst dann mit einer Liste zurecht, wenn sie nur die "Minimalanforderungen" erfüllt. Eine "starre" Parametrisierung mit [c]<C extends Comparable<C>>[/c] würde z.B. in diesem Fall nicht weiterhelfen:

Java:
List<Timestamp> timestamps = Arrays.asList(new Timestamp(17), new Timestamp(18), new Timestamp(5));
System.out.println(maximum(timestamps)); //funktioniert

List<? extends Date> dates = timestamps;
System.out.println(maximum(dates)); //funktioniert auch
 

tsitra

Bekanntes Mitglied
Hallo,

hier nochmal, möglicherweise redundant, noch eine Beschreibung bzw. Erklärung von mir:

Haben wir z.B. eine Methode

Java:
void checkFruit(List<? extends Obst> obstlist1) { ...}

Konkrete Parameter für checkFruit(...) können hier sein arrliBirne oder arrliApfel mit:
Java:
List<Birne> arrliBirne = new ArrayList<Birne>();
List<Apfel> arrliApfel = new ArrayList<Apfel>();
(sofern "class Birne extends Obst{}" und "class Apfel extends Obst{})

aber NUR DANN wenn keine add() auf obstlist1 aufgerufen wird,
also zum Beispiel kein "obstlist1.add(new Apfel());" innerhalb checkFruit(...) ausgeführt wird.
Denn es könnte ja als konkret übergebene Liste gerade eine ANDERS typisierte sein als "Apfel".

Da nicht klar ist, welche Liste dann konkret kommt, darf kein add() verwendet werden,
wenn <? extends Obst> als Typisierung verwendet wird.
Sonst würde es leicht dazu kommen, dass man einer Apfel-Liste Birnen-Objekte
hinzufügen wollte oder umgekehrt.

Viele Grüße
tsitra
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
mrStudent <? extends T> und <? super T> Java Basics - Anfänger-Themen 1
berserkerdq2 Größter unterschied von extends thread und implements runnable? Java Basics - Anfänger-Themen 2
N Variabel in eine class mit "extends JLabel" übertragen Java Basics - Anfänger-Themen 2
J extends Problem Java Basics - Anfänger-Themen 2
N extends und super vs new object Java Basics - Anfänger-Themen 4
JavaTalksToMe Extends/Implements Frage Java Basics - Anfänger-Themen 3
D public ArrayList(Collection<? extends E> c); Java Basics - Anfänger-Themen 2
CptK Interface Klasse Frame (extends JFrame) aus anderer Klasse schließen Java Basics - Anfänger-Themen 7
J Implements und Extends Java Basics - Anfänger-Themen 5
C Was macht `public class ClassName<T extends Comparable<T>>`? Java Basics - Anfänger-Themen 14
J Compiler-Fehler Fehler bei Vektor (E extends Object declared in class Vector) Java Basics - Anfänger-Themen 9
M mehrere extends? Java Basics - Anfänger-Themen 19
J doppelname nach schlüsselwort extends Java Basics - Anfänger-Themen 4
V Was bewirkt das Schlüsselwort extends in Verbindung mit class bzw. public class ? Java Basics - Anfänger-Themen 2
T extends und implements Java Basics - Anfänger-Themen 11
Crazynet 2 extends Java Basics - Anfänger-Themen 22
S Wrapper Klasse und extends Java Basics - Anfänger-Themen 2
W Methoden Rückgabedatentyp java.util.Map<java.lang.String,? extends ...> Java Basics - Anfänger-Themen 4
R Vererbung Übergabe von Variablen der Superklasse an Subklasse mit "extends" Java Basics - Anfänger-Themen 5
K Erste Schritte Extends Implements Java Basics - Anfänger-Themen 4
S Threads Thread wenn extends schon vergeben Java Basics - Anfänger-Themen 8
vandread Java Wildcards - Wann super wann extends? Java Basics - Anfänger-Themen 2
F Anfängerfrage zu extends Java Basics - Anfänger-Themen 12
B addAll(Collection<? extends E> c) Java Basics - Anfänger-Themen 9
T Input/Output StructuredFileReader extends BufferedReader Java Basics - Anfänger-Themen 6
K Erste Schritte extends vererbung Java Basics - Anfänger-Themen 15
P Class<? extends Entity> Array Java Basics - Anfänger-Themen 9
A final und extends Java Basics - Anfänger-Themen 14
Y Threads extends Thread oder implements Runnable Java Basics - Anfänger-Themen 10
C Vererbung "extends" umgehen mittels Objekterzeugung?! Java Basics - Anfänger-Themen 29
L Implements<-->extends und Interface Java Basics - Anfänger-Themen 10
S Klasse extends HashMap Java Basics - Anfänger-Themen 20
L Problem mit Vererbung (extends) cannot find symbol Java Basics - Anfänger-Themen 3
D MyActionListener extends Thread Java Basics - Anfänger-Themen 3
H2SO3- Designfragen (mehrfach extends) Java Basics - Anfänger-Themen 11
G Unterschied e extends y vs ? extends y Java Basics - Anfänger-Themen 5
X List von Klasse B als List von Klasse A (B extends A) Java Basics - Anfänger-Themen 2
H extends Locale Java Basics - Anfänger-Themen 4
O import ja....extends nein Java Basics - Anfänger-Themen 5
G Muss es immer extends sein ? Java Basics - Anfänger-Themen 9
N class Test<E extends MyAbstractClass> => typ von E? Java Basics - Anfänger-Themen 5
K mehrere Extends Java Basics - Anfänger-Themen 2
S extends Vector<xyz> Java Basics - Anfänger-Themen 10
S new .() extends JDialog {.} Java Basics - Anfänger-Themen 15
S extends und Konstruktor Java Basics - Anfänger-Themen 8
E Interface extends Observable Java Basics - Anfänger-Themen 13
G Wiedermal vererbung, extends JDialog extends Exception ? Java Basics - Anfänger-Themen 8
U extends JLabel & Thread Java Basics - Anfänger-Themen 2
G Innere klasssen unde "extends" klassen definieren, Java Basics - Anfänger-Themen 2
frau-u JMenu mit extends JPanel? Java Basics - Anfänger-Themen 4
G "extends DBConnection" funktioniert nicht Java Basics - Anfänger-Themen 15
N extends / implements / static, bedeutung ?? Java Basics - Anfänger-Themen 12
C Problem mit Zeichnen auf einer extends Canvas Class... Java Basics - Anfänger-Themen 2

Ähnliche Java Themen

Neue Themen


Oben