5 Stimmen

Wie kann ich einen Typkonstruktor in einer konkreten Klasse durch die Schnittstelle erzwingen, die sie implementiert?

Lassen Sie mich die Situation beschreiben, und ich bin mir sicher, dass ich dieses Problem nur falsch sehe. Ich habe eine konkrete Klasse, die eine Schnittstelle implementieren wird. Ich möchte in dem Vertrag erzwingen, dass die Klasse einen Konstruktor mit einem bestimmten Typ haben muss. Also zum Beispiel:

interface MyInterface {}
public class MyClass implements MyInterface {
    public MyClass(HashMap<String, String> params) {

    }
}

Ich möchte sicherstellen, dass MyClass mit einem einzigen HashMap-Argument instanziiert wird, was scheint, wie es getan werden würde, etwas wie dieses:

interface MyInterface<T>

Andere als mit Generika auf Methode Signaturen, ich habe nie verwendet Sie mit Klassen oder Schnittstellen, und ich bin wirklich ein Anfänger mit, so erklären Sie bitte alle Generika mit der Lösung beteiligt... oder die alternative Lösung, wenn ich über diese falsch (architektonisch gesehen) denke. Vielen Dank!

4voto

penpen Punkte 720

Sie können in Java keinen Vertrag für Konstruktoren mit Schnittstellen erzwingen. Die beste Annäherung ist die Definition einer Schnittstelle für eine Fabrik, mit einer create() Methode, die eine einzelne HashMap ...

Sie können die Schnittstelle auch durch eine abstrakte Klasse ersetzen, für die der Konstruktor eine HashMap die die Unterklassen dazu zwingt, einen, aber nicht mehrere Parameter anzugeben (die Unterklassen haben nicht unbedingt einen HashMap-Parameter).

4voto

Robert Munteanu Punkte 64955

Ergänzend zu den obigen Antworten ist ein Konstruktor ein Implementierungsdetail. Eine Schnittstelle definiert einen Vertrag, der beschreibt, wie sie sich verhält, nicht wie sie zusammengesetzt ist.

Aus diesem Grund kann man einen Implementator nicht zwingen, einen bestimmten Konstruktor zu haben. Ich denke, dass, was auch immer Sie zu tun versuchen, eine Schnittstelle nicht der richtige Weg ist.


Update : Diese Werkzeug zur Bearbeitung von Kommentaren Artikel beschreibt, wie Sie eine Anmerkung und einen Anmerkungsprozessor erstellen können, die wirksam werden zur Kompilierzeit und überprüfen, ob eine Klasse einen No-Arg-Konstruktor hat.

Sie kann so angepasst werden, dass sie für einen Konstruktor mit einem Argument funktioniert, der eine Map-Instanz annimmt.

Um den Artikel zu zitieren, würde die Verwendung in etwa so aussehen:

@NoArgsConstructor
public abstract class NoArgsSuperClass {
  public NoArgsSuperClass() {
  }
}

// Passes
public class PublicNoArgsConstructor extends NoArgsSuperClass {
  public PublicNoArgsConstructor() {
  }
}

// Fails
public class NonPublicConstructor extends NoArgsSuperClass {
  NonPublicConstructor() {
  }
}

0voto

REA_ANDREW Punkte 10426

Anstelle einer Schnittstelle müsste man eine abstrakte Klasse erstellen, den Konstruktor darin deklarieren und dann müsste jede Klasse, die davon erbt, den Basiskonstruktor aufrufen. Der Standardkonstruktor innerhalb der Basisklasse könnte auch privat sein.

Andrew

0voto

Jesper Punkte 193903

In Java ist es nicht möglich, eine Klasse zu zwingen, einen Konstruktor mit bestimmten Argumenttypen zu implementieren. Warum sollten Sie das tun? Normalerweise ist es nicht sinnvoll, dies zu tun.

Sie können eine nicht-abstrakte Klasse zwingen, eine bestimmte Methode zu implementieren, indem Sie die Klasse dazu bringen, eine Schnittstelle zu implementieren oder eine abstrakte Klasse zu erweitern, in der diese Methode deklariert (aber nicht definiert) ist. Das ist wegen der Polymorphie nützlich; Sie können eine Variable vom Typ der Oberklasse auf eine Instanz der Unterklasse verweisen lassen und die Methode aufrufen:

interface Animal {
    void makeSound(); }
}

class Dog implements Animal {
    void makeSound() {
        System.out.println("Woof!");
    }
}

// Later:

Animal a = new Dog();
a.makeSound();

Jetzt können Sie anrufen makeSound() ohne zu wissen, dass a bezieht sich auf eine Dog ; Sie wissen, dass das Objekt, das a verweist, hat eine makeSound() Methode, weil sie in der Schnittstelle deklariert ist Animal (und a ist ein Animal ).

Bei Konstruktoren rufen Sie einen Konstruktor nie polymorph auf, sondern immer unter Angabe des Namens der konkreten Klasse, die Sie instanziieren wollen. Aus diesem Grund ist es nicht sehr sinnvoll, eine Klasse zu zwingen, einen Konstruktor mit bestimmten Parametern zu haben.

Der einzige Fall, in dem dies nützlich sein könnte, ist die dynamische Instanzierung von Klassen über Reflection. Durch Reflection können Sie herausfinden, welche Konstruktoren eine Klasse hat, und einen davon dynamisch aufrufen. Sie könnten dann eine Ausnahme auslösen, wenn die Klasse nicht den spezifischen Konstruktor hat, den Sie benötigen - aber es gibt keine Möglichkeit, dies zur Kompilierzeit zu überprüfen.

0voto

Alexander Pogrebnyak Punkte 43705

Versuchen Sie, ein Objekt vom Typ MyInterface durch Reflexion zu erstellen?

Die Werksschnittstelle ist eine viel einfachere und bessere Alternative.

Definieren Sie eine Fabrikschnittstelle (Sie können sie sogar als innere Schnittstelle in MyInterface definieren).

interface MyInterface {
  public static interface Factory {
    create( HashMap< String, String > params );
  }
}

Wo auch immer neue Objekte von MyInterface erstellt werden, stellen Sie sicher, dass dies nur durch MyInterface.Factory .

Zu einer Frage der Generika. Aus dem Code, wie Sie zur Verfügung gestellt MyInterface sieht nicht generisch auf allen

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X