2013-08-26 8 views
7

Ich möchte eine generische Schnittstelle für diese zwei Klassen erstellen, aber ich bin mir nicht sicher, wie man die Generika richtig spezifiziert.Generische Schnittstelle auf eigene Klasse beschränken

public class ThingA implements Thing { 
    public ThingA createCopy(ThingA original); 
} 

public class ThingB implements Thing { 
    public ThingB createCopy(ThingB original); 
} 

Ich habe es versucht dies.

public interface Thing<V extends Thing<V>> { 
    public V createCopy(V original); 

} 

Aber ich bin immer noch in der Lage, Dinge wie diese zu tun, die nicht erlaubt sein sollten.

public class ThingB implements Thing<ThingA> { 
    public ThingA createCopy(ThingA original); 
} 

Antwort

6

Es gibt keine this Schlüsselwort Generika (noch für Methoden Parameter und Rückgabewerte Deklaration) und damit können Sie nicht genau das tun, was Sie wollen.

Mit anderen Worten ermöglicht die Schnittstelle, sicherzustellen, dass alle Methoden in der Klasse konsistente Typen verwenden, aber nicht den Klassentyp selbst referenzieren.

0

Suchen Sie

public interface Thing<V> { 
    public V createCopy(V original); 
} 

? Wenn nicht, können Sie genauer erklären, was es für Sie bedeutet, "eine generische Schnittstelle für zwei Klassen zu erstellen"?

+1

Dies erlaubt ihm immer noch genau das zu tun, was er nicht will. Generics hindert Sie nicht daran, nur einen Typ von Klasse zu verwenden, da dies das genaue Gegenteil von Generika ist. – giorashc

1

Dies ist nicht möglich. Und dafür ist Generika nicht da. Generics ist für Typ Sicherheit, d. H. Vermeidung von Güssen. Wenn jemand eine Klasse macht ThingB, die Thing<ThingA> irgendwie implementiert, dann großartig. Es ist perfekt typsicher. Warum kümmert dich das? Wie behindert es, was du tust?

0

Falls Sie frei Erweiterung zu verwenden, anstatt der Implementierung, dann könnte man, dass diese Art und Weise tun:

public interface Thing { ... } 
public abstract class Copyable { 
    public final Copyable copy() { 
     Copyable clone = createCopy(); 
     if (clone.getClass() != getClass()) 
      throw new RuntimeException("Copy has wrong type!"); 
     return clone; 
    } 
    protected abstract Copyable createCopy(); 
} 

Und es dann gerne verwenden:

public class Test extends Copyable implements Thing { 
    public String content = null; 

    @Override 
    public Copyable createCopy() { 
     Test clone = new Test(); 
     clone.content = this.content; 
     return clone; 
    } 
} 

/*code somewhere*/ { 
    Test t1 = new Test(); 
    t1.content = "Hello world!"; 
    Test t2 = (Test)t1.copy(); 
    System.out.println(t2.content); 
} 

Ein Problem dabei ist dass Copyable keine Schnittstelle ist. Dies kann jedoch ohne großen Aufwand, wie im Beispiel gezeigt, verwendet werden, aber die verwendete Klassenprüfung wird nicht auf Sprachenebene unterstützt. Mit anderen Worten, die createCopy abstrakte Methode ist nicht auf die Klasse beschränkt, die sie kopiert, und all das ist Sache des Programmierers, der die Klasse Copyable oder eine Klasse erweitert, die sie erweitert.

Die positive Seite, ist, dass, wenn Sie die .copy() auf das Objekt aufrufen, es ein Objekt zurückgegeben werden muss, das selbe wie sich selbst ist. Anstelle einer Ausnahme können Sie null zurückgeben, wenn Sie möchten. Dann hast du gut oder nichts.

Aber um ehrlich zu sein, ich verstehe nicht wirklich, warum Ihre createCopy lokale Methode einen Parameter hat. Es könnte sein, dann eine statische Methode ... altrough ich kann nicht einmal vorstellen, was in diesen Codeblock gehen würde:

static <X extends Thing> X copy(X object) { ... } 

können Sie die pratice mit einer statischen generischen Methode und das Ergebnis wird etwas freundlicher kombinieren könnten :

public interface Thing extends Cloneable { 
    public static <X extends Thing> X copy(X thing) { 
     Object clone = thing.clone(); 
     if (clone.getClass() != getClass()) 
      throw new RuntimeException("Copy has wrong type!"); 
     return (X)clone; 
    } 
} 

public class ThingA implements Thing { 
    public Object clone() { ... } 
} 

/*code somewhere*/ { 
    ThingA a1 = new ThingA(); 
    ThingA a2 = Thing.copy(a1); 
} 

Dennoch wird das Klonierungsverfahren durch eine Ausnahme geregelt statt Sprache Beschränkung, aber ich denke, das ist weit die beste Lösung ist.

Verwandte Themen