2008-11-24 21 views
9

Wie kann ich diese Java-Sammelform erstellen?Wie kann ich diese Java-Sammelform erstellen?

public interface IField { 

} 


class Field implements IField { // package private class 

} 

public class Form { 
    private List<Field> fields; 


    public List<IField> getFields() { 
    return this.fields; 

    } 

} 

Die return-Anweisung führt einen Compiler-Fehler (ich kenne den Grund - ich Generika Tutorial lesen), aber es wäre sehr nützlich sein, einen solchen Code zu schreiben.

Wenn ich "Felder" als Liste deklariert habe, müsste ich in anderen Methoden einer Form-Klasse viele Umwandlungen zu Feld verwenden.

Kann ich diesen verdammten Compiler zwingen, seine Regeln zu beugen und diese Return-Anweisung zu kompilieren?

Vielen Dank im Voraus.

+0

Als Randnotiz wird this.fields als this.fiedls typoed und ich bearbeiten nicht hoch genug rep müssen Beiträge anderer Leute. – Powerlord

+0

@R Bemrose - behoben, danke. –

Antwort

17

Eine bessere Lösung, IMO, ist die Signatur Ihrer Methode zu ändern, um eine beschränkte Platzhalter zu verwenden:

public List<? extends IField> getFields() 

Dies wird der Anrufer behandeln alles kommt „out“ die Liste als IField lassen, aber Der Aufrufer kann nichts hinzufügen (ohne Casting oder Warnungen), da er nicht weiß, was der "echte" Typ der Liste ist.

+1

Der Nachteil dieses Ansatzes ist, dass es den Aufrufer zwingt, Wildcards zu behandeln. Als generellen Grundsatz würde ich vorschlagen (und IIRC Generika Autoren haben vorgeschlagen) nur Platzhalter für Methodenparameter und vermeiden sie auf Rückgabetypen. – JodaStephen

+0

Es hängt vom Anwendungsfall ab, IMO. Wenn die Idee ist, dass dies wirklich nur eine Sammlung ist, von der gelesen werden soll, macht die Wildcard Sinn (und drückt genau aus, was verfügbar ist). Wenn es auch beschreibbar sein soll, wird es eindeutig nicht funktionieren - und sollte es auch nicht. –

+0

könnte U diese Frage anzeigen? http://stackoverflow.com/questions/314203/overidin-methods-by-return-type-in-java –

12

Wie Sie können, können Sie, weil Java-Generics nur gepfropft sind, nicht Teil des Typsystems.

Sie können

return (List<IField>)(Object)this.fields; 

tun, weil alle List<T> Objekte der gleichen zugrunde liegenden Typ sind.

Denken Sie daran, dass dies jedem erlaubt, einen beliebigen Typ zu implementieren, der in Ihrer Liste implementiert. Wenn Ihre Sammlung nicht schreibgeschützt ist, können Sie in Schwierigkeiten geraten.

+0

Ich werde es natürlich nur lesen lassen - danke U. –

0

Sonnenlicht ist richtig, Sie können es einfach werfen.

Eine andere Lösung ist, zu überprüfen, ob Sie wirklich eine List<Field> benötigen, oder ob Sie Ihre interne fields Variable zu List<IField> ändern können.

Solange Sie nur Methoden für den Inhalt der Liste verwenden, die sich auf der Schnittstelle befinden, sollten Sie in der Lage sein, einen starken Swap durchzuführen.

5

Tun Sie es nicht.

Ein List<Field> ist kein List<IField>. Sie können versuchen, den Compiler zum Akzeptieren zu zwingen (ich dachte, es wäre nicht möglich, ich wünschte, es wäre nicht möglich), aber das wird Sie in Schwierigkeiten bringen. Der Compiler ermöglicht es einem Benutzer, das von IField stammende AnotherField in die angegebene Liste einzuführen, indem es Ihre Invarianten bricht und in die Typsicherheit eingreift, die Generika bereitstellen. Spätere Verwendung der List<Field> wird brechen, da die Extraktion des seltsamen Elements die implizite Umwandlung in Field fehlschlägt, wo Sie nicht erwarten, dass es passiert.

Wenn Sie eine List<IField> anstelle von List<Field> zurückgeben müssen, empfehle ich, eine neue Liste mit den gleichen Elementen zu erstellen. Wenn Sie Ihre Schnittstelle ändern können, gehen Sie für Jon Skeets Lösung.

2

Wenn der Anrufer muss nicht die Liste ändern können:

return Collections.<IField>unmodifiableList(this.fields); 
Verwandte Themen