2010-10-16 3 views
6

Als praktisches Beispiel für die allgemeine Frage in diesem Thema, würde Ich mag die containsAll Methode in der Set Schnittstelle mitInterface-Implementierung mit Methode Argument Super

public boolean containsAll(Iterable<?> c) { /* ... */ } 

ich dies sollte erlaubt sein Abbildung implementieren, da Collection ist Iterable Bedeutung so ein containsAll würde die Schnittstellenanforderung abdecken. Ebenso scheint es im Allgemeinen möglich zu sein, Interfaces mit Superklassen von Argumenten zu implementieren.

Allerdings sagt Eclipse nicht (habe nicht gerade javac ausprobiert) - kann jemand den Grund dafür erklären? Ich bin mir sicher, dass es etwas in der Spezifikation gibt, das es so macht, wie es ist, aber ich würde gerne auch die Motivation für die Anforderung verstehen. Oder fehlt mir etwas wie Iterable<?> nicht eine Oberklasse von Collection<?>?

Als eine Nebenfrage - gegeben ich zwei Methoden deklarieren würde die Methode mit der Iterable Signatur immer auf Anrufe mit einem Collection Argument bevorzugt werden?

Eclipse-Fehler:

Wenn ich entfernen Sie die Methode mit dem Collection Unterschrift, nur verlassen die Iterable ein (siehe nach Fehler), erhalte ich folgendes:

The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)

Die genaue Wesen Umsetzung :

@Override public boolean containsAll(Collection<?> c) { 
    for (Object o : c) if (!contains(o)) return false; 
    return true; 
} 
public boolean containsAll(Iterable<?> c) { 
    for (Object o : c) if (!contains(o)) return false; 
    return true; 
} 
+0

Konnten Sie einen Fehler bekannt geben, den Eclipse Ihnen gibt? Funktioniert für mich in IDEA. –

+0

@Nikita: bearbeitet in. Soooo ... könnte es nur eine Eclipse-Sache sein? – Carl

+0

Dies ist ein Begriff Alptraum. Ich laufe vor solchen Herausforderungen davon. – skaffman

Antwort

2

Meine Vermutung, warum Java Diese Einschränkung hat, sagen Sie.

Sagen Sie zum Beispiel C erweitert A direkt auf den ersten, zwingende void foo(String s), und dann wurde es geändert B. In diesem Fall foo C bestehenden Überschreibung von foo wäre ungültig, weil B sollte alle Object s verarbeiten können zu verlängern, nicht nur String s.

+0

Ah, das scheint eine vernünftige Erklärung zu sein - die Erweiterung der Schnittstelle würde verlangen, dass Unterklassen die erweiterte Schnittstelle beibehalten. Dennoch scheint es so zu sein, dass es erlaubt sein sollte - typischerweise dürfen Unterklassen keine Schnittstellen eingrenzen. – Carl

+0

Es macht wahrscheinlich auch das Design der virtuellen Tabelle klarer zu behaupten, dass alle Methoden darin die genaue Signatur haben. Oder vielleicht dachten sie einfach, dass sie es schaffen könnten, wenn sie es ausreichend ausschöpften, aber kein zwingendes Bedürfnis sahen und es ausließen. – oksayt

+0

Ich vermisse etwas - soll das Beispiel funktionieren? Auf der Annotation @Override bekomme ich "Methode überschreibt die Methode nicht von ihrer Oberklasse". – Amalgovinus

5

Da die Schnittstelle, die Sie implementieren, die (abstrakte) Schnittstelle deklariert Methode containsAll(Collection<?>), müssen Sie es mit dieser genauen Signatur implementieren. Java erlaubt Ihnen nicht, eine Methode mit einem breiteren Parametertyp als dem Original zu implementieren/zu überschreiben. Aus diesem Grund erhalten Sie den Fehler, den Sie anzeigen, wenn Sie Ihre Methode mit der Collection-Signatur auskommentieren.

Sie zeigen nicht den anderen Fehler, den Sie behaupten, wenn die Methode nicht auskommentiert ist, aber ich denke, es könnte etwas mit mehrdeutiger Methode Überladung zu tun haben. Jetzt

class A { 
    void foo(String s) { ... } 
} 

class B extends A { 
    // Note generalized type 
    @Override void foo(Object s) { ... } 
} 

wenn Sie class C extends B haben und es will foo außer Kraft zu setzen, es ist nicht klar, was Argument sollte es dauern:

+0

Es gibt keinen Fehler, wenn die Methode nicht auskommentiert ist. Nur wenn derjenige mit der 'Collection'-Signatur ist. – Carl

+0

Auch jede Einsicht, warum dies der Fall ist? Geht es nach @ oksayts Antwort? – Carl

+0

@Carl, Sie meinen, warum Java so konzipiert ist? Könnte sein. –

0

Die Argumenttypen sind Teil der Methodensignatur, daher benötigt der jvm eine Methode mit genau der gleichen Signatur, um Überschreibungen zu finden. Ein containsAll (Iterable) hat eine andere Signatur als containsAll (Collection).

Wenn ich mich recht erinnere, muss der Compiler einige Workarounds verwenden, um Generika trotz dieser Einschränkung arbeiten zu lassen.

Zu Ihrer zweiten Frage würde der Compiler das Collection-Argument bevorzugen, da es ein Untertyp von Iterable ist, was die Collection-Methode spezifischer als die Iterable-Methode macht.