Question

J'ai un groupe de classe qui implémente une interface commune: Command.

Et ce groupe de classe se dirige vers une carte.

Pour que la mappe fonctionne correctement, chaque classe qui implémente Command doit implémenter Command afin de remplacer la méthode Object.equals (Object other) .

ça va.

Mais je voudrais forcer le dépassement d'égaux. = > Vous avez une erreur de compilation lorsque quelque chose qui implémente la commande ne remplace pas égal à égal.

C'est ce possible?

Éditer: BTW, je devrai aussi forcer le remplacement du hashcode ...

Était-ce utile?

La solution

Non, vous ne pouvez pas. Cependant, vous pouvez utiliser une classe de base abstraite au lieu d’une interface et rendre equals () abstract:

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

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

Les sous-classes de la Commande doivent fournir ensuite leurs propres méthodes equals et hashCode.

Il est généralement déconseillé de forcer les utilisateurs d'API à étendre une classe de base, mais cela peut être justifié dans ce cas. De même, si vous faites de Command une classe de base abstraite au lieu d'une interface, plutôt que d'introduire une classe de base artificielle dans addition à l'interface de commande, votre API ne court aucun risque. les utilisateurs se trompent.

Autres conseils

Pouvez-vous étendre vos objets à partir d'un XObject abstrait plutôt que java.lang.Object?

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

Les classes abstraites ne fonctionneront pas si vous avez un petit-enfant, car son père a déjà surchargé les méthodes equals et hashCode. Votre problème est donc à nouveau résolu.

Essayez d’utiliser les annotatins et APT ( http: // docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html ) pour y parvenir.

Cela ne serait possible que si Command était une interface ou une classe abstraite, où equals (..) est une méthode déclarée abstraite.

Le problème est que Object, qui est la superclasse de tous les objets, définit déjà cette méthode.

Si vous souhaitez indiquer qu'il s'agit d'un problème (au moment de l'exécution), vous pouvez déclencher une exception afin de forcer les utilisateurs de votre API à le remplacer. Mais ce n’est pas possible au moment de la compilation, du moins à ma connaissance.

Essayez de contourner ce problème en utilisant une méthode spécifique à l’API, par exemple. CommandEquals. L’autre option est (comme mentionné) d’étendre une autre classe qui définit une méthode abstraite Equals.

Vous pouvez créer boolean myEquals () dans la commande d'interface et créer un adaptateur comme suit:

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

Ensuite, vous utilisez simplement map.put (clé, nouveau MyAdapter (commande)) au lieu de map.put (clé, commande)

Eh bien, si vous voulez une vérification à l'exécution, vous pouvez faire quelque chose comme:

    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();
    }
}

Imprimera vrai pour le premier et faux pour le second. Si vous le souhaitez, le temps de compilation semble être la seule option possible: créer une annotation et utiliser un outil de traitement d'annotation pour vérifier que toutes les classes annotées sont égales.

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.");
    }
}

Étant donné que equals () est hérité de Object , je doute que vous ne puissiez pas forcer cela, car pour chaque type , il existe un implémentation héritée de equals () disponible.

Je ne pense pas qu'il soit possible de forcer le remplacement d'égaux car ils proviennent de la classe Object.

Sur une note connexe, notez que vous devez remplacer la méthode 'hashCode' à partir de la classe Object chaque fois que vous substituez la valeur égale. Cela devient particulièrement important si vous allez utiliser des instances de vos classes en tant que clés d'une carte. Vérifiez cet article: http://www.artima.com/lejava/articles/equality.html qui fournit des indications sur la façon de remplacer correctement d’une manière correcte

Comme les autres réponses l'ont déjà expliqué, non, vous ne pouvez pas forcer le genre de chose que vous essayez.

Une chose qui pourrait fonctionner "assez" est de définir une deuxième interface, appelez-la MappableCommand.

public interface MappableCommand 
{

}

Dans votre documentation pour cette interface, indiquez qu'une classe ne doit implémenter cette interface (vide) que si le concepteur de la classe a pris en compte les exigences que vous avez définies.

Ensuite, vous pouvez définir le type de valeur de votre carte sur MappableCommand; seules les commandes MappableCommands pourront être ajoutées à la carte.

Ceci est similaire à la logique derrière la nécessité d'implémenter l'interface (vierge) Serializable pour les classes pouvant être sérialisées par les mécanismes de sérialisation par défaut de Java.

Si cela ne fonctionne pas, vous devrez peut-être renvoyer une erreur d'exécution;

Faux éditer:

Si vous souhaitez rendre cette exigence plus évidente, vous pouvez définir la nouvelle interface de cette façon

public interface MappableCommand 
{

    public void iOverrodeTheEqualsMethod();

    public void seriouslyIPromiseThatIOverrodeIt();

}

Voici une variante de certaines des solutions proposées:

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

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

Ou si vous voulez vraiment en être sûr, utilisez un hashmap vérifié; par exemple

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

Mais peu importe ce que vous faites, vous ne pouvez empêcher quelqu'un de le faire:

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

J'ai tendance à penser que ce genre de choses va poser problème à l'avenir. Par exemple, supposons que j'ai un groupe de classes de commandes existantes qui étendent une autre classe de base et que, indirectement, remplacer est égal à et hashcode de la manière prescrite. Le problème est que je ne peux pas utiliser ces classes. Au lieu de cela, je suis obligé de les réimplémenter ou d'écrire un tas de wrappers.

OMI, c’est une mauvaise idée d’essayer de forcer le développeur à adopter un modèle de mise en œuvre particulier. Il serait préférable de mettre de forts avertissements dans les Javadocs et de faire appel aux développeurs pour faire le bon choix .

Pouvez-vous fournir votre propre java.util.comparator à la carte en question?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top