2011-01-05 4 views
1

Ich verstehe, warum ich kann folgendes nicht tun:Kann ich eine generische Liste erstellen, in der ich einen Typ und einen Untertyp hinzufügen kann?

private class Parent { 
}; 

private class Child extends Parent { 
}; 

private class GrandChild extends Child { 
}; 

public void wontCompile(List<? extends Parent> genericList, Child itemToAdd) { 
    genericList.add(itemToAdd); 
} 

Meine Frage ist es eine praktische Möglichkeit, eine typsichere Liste zu haben, wo Sie Anruf hinzufügen können (E), wobei E bekannt ist, nur ein Elternteil oder ein Kind zu sein ?

Ich erinnere mich vage an eine Verwendung des "|" Operator wie für Platzhalter verwendet, aber ich kann es nicht in der Spezifikation finden ...

Vielen Dank!

+0

http://en.wikipedia.org/wiki/Liskov_substitution_principle sagt, dass Sie das nicht wollen/müssen . – ILMTitan

Antwort

0

Gibt es nicht.

In add(E) konnte die Bestimmung des genauen Typs von E nur zur Laufzeit erfolgen. Jede Variable, die als Typ Parent deklariert ist, kann aufgrund der Untertypbeziehung eine Referenz auf ein GrandChild-Objekt enthalten. Es gibt keine Möglichkeit, eine Liste zu erstellen, in der Sie nicht Objekte eines Untertyps des Elementtyps hinzufügen können (zumindest, wenn eine solche Operation vom Compiler verboten wird).

Die eigentliche Frage ist: Warum willst du das überhaupt? Vielleicht steht Ihre Vererbungshierarchie auf dem Kopf.

+0

Es ist ein Vermächtnis Problem. Die Swing-API ist nicht generisch und erfordert viele Unterklassen. Dementsprechend gibt es in dem Code, den ich gerade geerbt habe, viele @Suppresswarnings für alle Rawtypes und ungeprüfte Verwendungen von Listen von Listenern, JMenuItems usw. Ich hoffte, die Typsicherheit dieses Codes zu verbessern und die meisten @Suppresswarnings zu entfernen . – LogicVictim

+0

Das erklärt nicht, warum Sie verhindern müssen, dass GrandChild-Instanzen zur Liste hinzugefügt werden. – davmac

-1

Sie können eine Fassade erstellen und Ihre eigene Instanz überprüfen, bevor Sie sie an eine gekapselte Liste delegieren.

Es wäre hässlich und ist wahrscheinlich eine schreckliche Idee.

0

Warum nicht? Alles, was Sie brauchen, ist ein passender generischer Typ sowohl für die Liste und Element Argumente, die sowohl der Aufrufparameter, Sie, das ist ziemlich einfach erreichen können:

import java.util.ArrayList; 
import java.util.List; 

public class TestClass { 

    private class Parent { 
    }; 

    private class Child extends Parent { 
    }; 

    private class GrandChild extends Child { 
    }; 

    public <T extends Parent> void compilesNow(final List<T> genericList, final T itemToAdd) { 
    genericList.add(itemToAdd); 
    } 

    public void addSomeDescendents() { 
    final List<Parent> list = new ArrayList<Parent>(); 
    compilesNow(list, new Parent()); 
    compilesNow(list, new Child()); 
    compilesNow(list, new GrandChild()); 
    } 
} 

EDIT: Sorry, ich das etwas verpaßt zu ohne jedoch ... Grandchild , mein Beispiel ist ein Schritt weiter in wie Generics verwendet werden können, um dieses Szenario mindestens zu kompilieren

Verwandte Themen