Ich weiß, dass es nicht möglich ist, einen Konstruktor in einer Schnittstelle zu definieren. Aber ich frage mich warum, weil ich denke, dass es sehr nützlich sein könnte.
Sie können also sicher sein, dass einige Felder in einer Klasse für jede Implementierung dieser Schnittstelle definiert sind.
Betrachten Sie beispielsweise die folgende Nachrichtenklasse:
public class MyMessage {
public MyMessage(String receiver) {
this.receiver = receiver;
}
private String receiver;
public void send() {
//some implementation for sending the mssage to the receiver
}
}
Wenn Sie eine Schnittstelle für diese Klasse definieren, damit ich mehr Klassen haben kann, die die Nachrichtenschnittstelle implementieren, kann ich nur die Sendemethode und nicht den Konstruktor definieren. Wie kann ich also sicherstellen, dass für jede Implementierung dieser Klasse wirklich ein Empfänger festgelegt ist? Wenn ich eine Methode wie diese verwende, setReceiver(String receiver)
kann ich nicht sicher sein, ob diese Methode wirklich aufgerufen wird. Im Konstruktor konnte ich es sicherstellen.
Antworten:
Nehmen Sie einige der Dinge, die Sie beschrieben haben:
... diese Anforderungen sind genau das, wofür abstrakte Klassen sind.
quelle
Message
Schnittstelle zu deklarieren , die diesend()
Methode definiert , und wenn Sebi eine "Basis" -Klasse für Implementierungen derMessage
Schnittstelle bereitstellen möchte , dann geben Sie auch eineAbstractMessage
an. Abstrakte Klassen sollten nicht an die Stelle von Schnittstellen treten, ich habe nie versucht, dies vorzuschlagen.Ein Problem, das auftritt, wenn Sie Konstruktoren in Schnittstellen zulassen, besteht in der Möglichkeit, mehrere Schnittstellen gleichzeitig zu implementieren. Wenn eine Klasse mehrere Schnittstellen implementiert, die unterschiedliche Konstruktoren definieren, müsste die Klasse mehrere Konstruktoren implementieren, von denen jeder nur eine Schnittstelle erfüllt, die anderen jedoch nicht. Es wird unmöglich sein, ein Objekt zu konstruieren, das jeden dieser Konstruktoren aufruft.
Oder im Code:
quelle
class A implements Named, HashList { A(){HashList(new list()); Named("name");} }
new Set<Fnord>()
dies so interpretiert werden könnte, dass es "Gib mir etwas, als das ich verwenden kannSet<Fnord>
" bedeutet. Wenn der AutorSet<T>
beabsichtigtHashSet<T>
, die Anlaufstelle für Dinge zu sein, für die kein besonderer Bedarf an etwas anderem besteht, kann die Schnittstellenew Set<Fnord>()
als Synonym für definiert werdennew HashSet<Fnord>()
. Die Implementierung mehrerer Schnittstellen durch eine Klasse wäre kein Problem, danew InterfaceName()
einfach eine von der Schnittstelle festgelegte Klasse erstellt würde .A(String,List)
Konstruktor könnte der designierte Konstruktor sein, undA(String)
undA(List)
sekundären diejenigen sein könnten , die es nennen. Ihr Code ist kein Gegenbeispiel, nur ein schlechtes.Eine Schnittstelle definiert einen Vertrag für eine API, dh eine Reihe von Methoden, auf die sich sowohl der Implementierer als auch der Benutzer der API einigen. Eine Schnittstelle hat keine instanziierte Implementierung, daher keinen Konstruktor.
Der von Ihnen beschriebene Anwendungsfall ähnelt einer abstrakten Klasse, in der der Konstruktor eine Methode einer abstrakten Methode aufruft, die in einer untergeordneten Klasse implementiert ist.
Das inhärente Problem hierbei ist, dass während der Ausführung des Basiskonstruktors das untergeordnete Objekt noch nicht erstellt wird und sich daher in einem unvorhersehbaren Zustand befindet.
Zusammenfassend: Ist es problematisch, wenn Sie überladene Methoden von übergeordneten Konstruktoren aufrufen , um mindprod zu zitieren :
quelle
Sie können versuchen, eine
getInstance()
Methode in Ihrer Schnittstelle zu definieren, damit der Implementierer weiß, welche Parameter behandelt werden müssen. Es ist nicht so solide wie eine abstrakte Klasse, bietet aber mehr Flexibilität als eine Schnittstelle.Für diese Problemumgehung müssen Sie jedoch die verwenden
getInstance()
, um alle Objekte dieser Schnittstelle zu instanziieren.Z.B
quelle
Es gibt nur statische Felder in der Schnittstelle, die während der Objekterstellung in der Unterklasse nicht initialisiert werden müssen, und die Methode der Schnittstelle muss die tatsächliche Implementierung in der Unterklasse bereitstellen. Daher ist kein Konstruktor in der Schnittstelle erforderlich.
Zweiter Grund: Während der Objekterstellung der Unterklasse wird der übergeordnete Konstruktor aufgerufen. Wenn jedoch mehr als eine Schnittstelle implementiert wird, tritt beim Aufruf des Schnittstellenkonstruktors ein Konflikt darüber auf, welcher Konstruktor der Schnittstelle zuerst aufgerufen wird
quelle
Wenn Sie sicherstellen möchten, dass jede Implementierung der Schnittstelle ein bestimmtes Feld enthält, müssen Sie lediglich den Getter für dieses Feld zu Ihrer Schnittstelle hinzufügen :
Receiver
Objekt auf irgendeine Weise an die Klasse übergeben werden muss (entweder vom Konstruktor oder vom Setter).quelle
Abhängigkeiten, auf die in einer Schnittstellenmethode nicht verwiesen wird, sollten als Implementierungsdetails betrachtet werden, nicht als etwas, das die Schnittstelle erzwingt. Natürlich kann es Ausnahmen geben, aber in der Regel sollten Sie Ihre Schnittstelle so definieren, wie das Verhalten erwartet wird. Der interne Status einer bestimmten Implementierung sollte kein Entwurfsanliegen der Schnittstelle sein.
quelle
In dieser Frage finden Sie das Warum (aus den Kommentaren entnommen).
Wenn Sie so etwas wirklich tun müssen, möchten Sie möglicherweise eine abstrakte Basisklasse anstelle einer Schnittstelle.
quelle
Dies liegt daran, dass Schnittstellen es nicht erlauben, den Methodenkörper darin zu definieren. Wir sollten jedoch den Konstruktor in derselben Klasse definieren müssen, wie Schnittstellen standardmäßig den abstrakten Modifikator für alle zu definierenden Methoden haben. Deshalb können wir keinen Konstruktor in den Schnittstellen definieren.
quelle
Hier ist ein Beispiel mit dieser Technik. In diesem Beispiel ruft der Code Firebase mit einem Mock auf
MyCompletionListener
, bei dem es sich um eine als abstrakte Klasse maskierte Schnittstelle handelt, eine Schnittstelle mit einem Konstruktorquelle
private
Zugriffsmodifikator mit verwendeninterface
?Im Allgemeinen dienen Konstruktoren zum Initialisieren nicht statischer Elemente einer bestimmten Klasse in Bezug auf das Objekt.
Es gibt keine Objekterstellung für die Schnittstelle, da nur deklarierte Methoden, aber keine definierten Methoden vorhanden sind. Warum wir für deklarierte Methoden kein Objekt erstellen können, ist nichts anderes als das Zuweisen von Speicher (im Heapspeicher) für nicht statische Mitglieder.
JVM erstellt Speicher für Mitglieder, die vollständig entwickelt und einsatzbereit sind. Basierend auf diesen Mitgliedern berechnet JVM, wie viel Speicher für sie erforderlich ist, und erstellt Speicher.
Bei deklarierten Methoden kann JVM nicht berechnen, wie viel Speicher für diese deklarierten Methoden benötigt wird, da die Implementierung in Zukunft erfolgen wird, was zu diesem Zeitpunkt noch nicht erfolgt. Daher ist die Objekterstellung für die Schnittstelle nicht möglich.
Fazit:
Ohne Objekterstellung gibt es keine Möglichkeit, nicht statische Elemente über einen Konstruktor zu initialisieren. Aus diesem Grund ist der Konstruktor in einer Schnittstelle nicht zulässig (da der Konstruktor in einer Schnittstelle nicht verwendet wird).
quelle