Frage

Ich habe eine Reihe von Klasse, die eine gemeinsame Schnittstelle implementieren: Befehl.

Und dieser Haufen Klasse geht auf eine Karte.

die Karte richtig funktionieren zu bekommen, muß ich jede Klasse, den Befehl implementiert die Object.equals(Object other) Methode außer Kraft zu setzen.

es ist in Ordnung.

Aber ich whould mag das übergeordnete von Gleichen erzwingen. => Einen Übersetzungsfehler hat, wenn etwas den Befehl implementieren nicht überschreiben entspricht.

Es ist das möglich?

Edit: Übrigens, ich werde auch brauchen die Überschreibung von Hash-Code zu zwingen ...

War es hilfreich?

Lösung

Nein, kann man nicht. Was Sie tun können, ist jedoch eine abstrakte Basisklasse verwendet statt einer Schnittstelle und equals() abstrakt machen:

abstract class Command {
   // put other methods from Command interface here

   public abstract boolean equals(Object other);
   public abstract int hashCode();
}

Subklassen von Command muss dann stellen ihre eigenen equals und hashCode Methoden.

Es ist generell eine schlechte Praxis API Benutzer zu zwingen, eine Basisklasse zu verlängern, aber es kann in diesem Fall gerechtfertigt werden. Auch, wenn Sie Command eine abstrakte Basisklasse statt einer Schnittstelle zu machen, anstatt eine künstliche Basisklasse Einführung in zusätzlich in die Kommandoschnittstelle, dann gibt es kein Risiko, dass Ihre API-Nutzer bekommt es falsch.

Andere Tipps

Können Sie Ihre Objekte von einer abstrakten XObject erweitern, anstatt java.lang.Object?

public abstract class XObject
 extends Object
{
@Override
public abstract boolean equals(Object o);
}

Abstrakte Klassen werden nicht funktionieren, wenn Sie ein Enkelkind haben, da sein Vater bereits beide equals und hashCode Methoden overrided und dann haben Sie Ihr Problem noch einmal.

Versuchen annotatins und APT mit ( http: // docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html ), um es getan.

Dies wäre nur möglich, wenn Befehl eine Schnittstelle ist, oder eine abstrakte Klasse, wo equals (..) ein Verfahren als abstrakt deklariert ist.

Das Problem ist, dass das Objekt, das die übergeordnete Klasse aller Objekte ist, diese Methode bereits definiert.

Wenn Sie angeben möchten, dass dies ein Problem (zur Laufzeit), können Sie eine Ausnahme auslösen, zu zwingen, die Benutzer des API es außer Kraft zu setzen. Aber es ist nicht möglich, bei der Kompilierung, zumindest mein Wissen.

Versuchen, um es zu umgehen, indem ein API-spezifische Verfahren, z.B. CommandEquals. Die andere Option ist (wie bereits erwähnt) eine andere Klasse erweitern, die definiert eine abstrakte Methode Equals.

Sie können boolean myEquals() in interface Command erstellen, und erstellen Sie Adapter wie folgt aus:

class MyAdapter{
  Command c;
  boolean equals(Object x) {
    return c.myEquals((Command)x);
  }
}

Sie dann nur verwenden map.put(key, new MyAdapter(command)) statt map.put(key, command)

Nun, wenn Sie wollen eine Laufzeit überprüfen Sie so etwas wie tun:

    interface Foo{

}
class A implements Foo {

}
class B implements Foo {
    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }
}

public static void main(String[] args) {
    Class<A> clazzA = A.class;
    Class<B> clazzB = B.class;

    Class<Object> objectClass = Object.class;
    try {
        Method methodFromObject = objectClass.getMethod("equals",Object.class);
        Method methodFromA = clazzA.getMethod("equals",Object.class);
        Method methodFromB = clazzB.getMethod("equals",Object.class);
        System.out.println("Object == A" + methodFromObject.equals(methodFromA));
        System.out.println("Object == B" + methodFromObject.equals(methodFromB));
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
}

Wird für die ersten und falsch für die zweiten wahr drucken. Wenn Sie wollen, dass es Zeit sieht aus wie die einzige Option kompilieren ist eine Anmerkung zu erstellen und Annotation Bearbeitungswerkzeug verwendet um zu überprüfen, dass alle kommentierten Klassen überschreiben Gleichen.

interface A{
    public boolean equal2(Object obj);
}

abstract class B implements A {

    @Override
    public boolean equals(Object obj) {
        return equal2(obj);
    }

}


class C extends B {

    public boolean equal2(Object obj) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

Da equals() von Object geerbt Ich bezweifle, man kann wirklich das nicht erzwingen, da für alle Typen gibt es eine automatische geerbte Implementierung von equals() zur Verfügung.

Ich glaube nicht, es möglich ist, überwiegende von Gleichen zu zwingen, wie es aus der Objektklasse kommt.

Auf einem verwandten beachten, beachten Sie, dass Sie von der Objektklasse außer Kraft setzen ‚hashCode‘ Methode müssen, wann immer Sie equals überschreiben. Dies wird espeically wichtig, wenn Sie Instanzen von Klassen als Schlüssel einer Karte verwenden wollen. Überprüfen Sie diesen Artikel: http://www.artima.com/lejava/articles/equality.html die einige Hinweise über liefert, wie gleich in der richtigen Art und Weise außer Kraft zu setzen

Wie die anderen Antworten haben bereits erklärt, nicht Sie die Art der Sache nicht zwingen können, den Sie versuchen zu.

Eine Sache, die ‚genug‘ funktionieren könnte ist eine zweite Schnittstelle zu definieren, rufen Sie diese ein MappableCommand.

public interface MappableCommand 
{

}

In Ihrer Dokumentation für diese Schnittstelle zeigt an, dass eine Klasse soll nur diesen (leer) Schnittstelle implementieren, wenn die Klasse Designer die Anforderungen betrachtet hat man festgestellt.

Dann können Sie den Werttyp Ihrer Karte zu MappableCommand, Satz und nur MappableCommands wird in der Lage sein, zu der Karte hinzugefügt werden.

Dies ist ähnlich wie die Logik hinter warum muss man den (leeren) Schnittstelle Serializable für Klassen implementieren, die von Java-Standard Serialisierungsmechanismen serialisiert werden kann.

Wenn das nicht funktioniert, dann können Sie für das Werfen eines Laufzeitfehlers begleichen müssen;

Gefälschte Edit:

Wenn Sie diese Anforderung noch deutlicher machen wollen Sie die neue Schnittstelle auf diese Weise definieren könnten

public interface MappableCommand 
{

    public void iOverrodeTheEqualsMethod();

    public void seriouslyIPromiseThatIOverrodeIt();

}

Hier ist eine Variation von einigen der anderen vorgeschlagenen Lösungen:

public abstract class CommandOverridingEquals implements Command {
    public abstract boolean equals(Object other);
    public abstract int hashcode();
}

Map<String, CommandOverridingEquals> map = 
    new HashMap<String, CommandOverridingEquals>();

Oder wenn Sie wirklich sicher sein wollen, verwenden Sie ein getestetes hashmap; z.

Map<String, CommandOverridingEquals> map = Collections.checkedMap(
    new HashMap<String, Command>(),
    String.class, CommandOverridingEquals.class);

Aber egal, was Sie tun, Sie nicht, dass jemand tun dies stoppen können:

public class AntiFascistCommand extends CommandOverridingEquals {
    public boolean equals(Object other) { return super.equals(other); }
    public int hashcode() { return super.hashcode(); }
    ...
}

Ich neige dazu, zu glauben, dass diese Art der Sache Mühe auf der Bahn verursacht. Angenommen, dass ich ein paar vorhandenen Befehlsklassen haben, die eine andere Basisklasse erweitern und (nebenbei bemerkt) Überschreibung equals und hashcode in der vorgeschriebenen Art und Weise. Das Problem ist, ich kann nicht diese Klassen verwenden. Stattdessen bin ich gezwungen, sie neu zu implementieren oder eine Reihe von Wrapper schreiben.

IMO, ist es eine schlechte Idee, zu versuchen, den Entwickler in einer bestimmten Implementierung Muster zu zwingen. Es wäre besser, einige starke Warnungen in den Javadocs zu setzen und sich auf die Entwickler zu das Richtige zu tun .

Ist es möglich, dass Sie Ihren eigenen java.util.comparator auf die Karte in Frage zu finden?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top