example and java interface override equals requirements

java - and - Forzar una clase para anular el método.equals



override equals c# (12)

Tengo un montón de clase que implementan una interfaz común: Comando.

Y este grupo de clase va a un mapa.

Para que el Mapa funcione correctamente, necesito que cada clase que implementa Comando Object.equals(Object other) el Object.equals(Object other) .

está bien.

Pero me gustaría forzar la anulación de iguales. => Tiene un error de compilación cuando algo que implementa comando no anula iguales.

Es así de posible?

Editar: Por cierto, también necesitaré forzar la anulación de hashcode ...


¿Es posible que proporciones tu propio java.util.comparator en el mapa en cuestión?


¿Puedes ampliar tus objetos desde un XObject abstracto en lugar de java.lang.Object?

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


Aquí hay una variación de algunas de las otras soluciones propuestas:

public abstract class CommandOverridingEquals implements Command { public abstract boolean equals(Object other); public abstract int hashcode(); } Map<String, CommandOverridingEquals> map = new HashMap<String, CommandOverridingEquals>();

O si realmente quiere estar seguro, use un hashmap verificado; p.ej

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

Pero no importa lo que hagas, no puedes evitar que alguien haga esto:

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

Tiendo a pensar que este tipo de cosas causará problemas en la pista. Por ejemplo, supongamos que tengo un grupo de clases de comandos existentes que amplían alguna otra clase base y (de paso) anulan equals y hashcode de la manera prescrita. El problema es que no puedo usar esas clases. En cambio, me veo obligado a volver a implementarlos o a escribir un montón de envoltorios.

OMI, es una mala idea tratar de forzar al desarrollador a un patrón de implementación particular. Sería mejor poner algunas advertencias fuertes en los Javadocs y confiar en que los desarrolladores hagan lo correcto .


Bueno, si quieres un control en tiempo de ejecución, puedes hacer algo como:

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

Se imprimirá verdadero para el primero y falso para el segundo. Si lo desea, el tiempo de compilación parece que la única opción es crear una anotación y usar la herramienta de procesamiento de anotaciones para verificar que todas las clases anotadas anulen las mismas.


Como las otras respuestas ya han explicado, no, no puedes forzar el tipo de cosa que estás tratando de hacer.

Una cosa que podría funcionar "suficiente" es definir una segunda interfaz, llamar a este MappableCommand.

public interface MappableCommand { }

En su documentación para esta interfaz, indique que una clase solo debe implementar esta interfaz (vacía) si el diseñador de la clase ha considerado los requisitos que usted indicó.

Luego puede establecer el tipo de valor de su mapa en MappableCommand, y solo MappableCommands podrán agregarse al mapa.

Esto es similar a la lógica detrás de por qué uno necesita implementar la interfaz (en blanco) Serializable para las clases que pueden ser serializadas por los mecanismos de serialización por defecto de Java.

Si esto no funciona, entonces puede que tenga que conformarse con arrojar un error de tiempo de ejecución;

Edición falsa:

Si quisiera hacer este requisito más obvio, podría definir la nueva interfaz de esta manera

public interface MappableCommand { public void iOverrodeTheEqualsMethod(); public void seriouslyIPromiseThatIOverrodeIt(); }


Dado que equals() se hereda de Object , dudo que no puedas forzarlo realmente, ya que para cada tipo hay una implementación heredada automática de equals() disponible.


Esto solo sería posible si Command fuera una interfaz, o una clase abstracta, donde equals (..) es un método declarado como abstracto.

El problema es que Object, que es la superclase de todos los objetos, ya define este método.

Si desea indicar que se trata de un problema (en tiempo de ejecución), puede lanzar una excepción para forzar a los usuarios de su API a que lo anulen. Pero no es posible en tiempo de compilación, al menos que yo sepa.

Intente solucionarlo, teniendo un método específico de API, por ejemplo, CommandEquals. La otra opción es (como se mencionó) extender otra clase que define un método abstracto Equals.



No creo que sea posible forzar la anulación de iguales ya que proviene de la clase Object.

En una nota relacionada, tenga en cuenta que debe anular el método ''hashCode'' de la clase Object siempre que anule Iguales. Esto adquiere especial importancia si va a utilizar instancias de sus clases como claves de un Mapa. Consulte este artículo: http://www.artima.com/lejava/articles/equality.html que proporciona algunos consejos sobre cómo anular iguales de manera correcta


No, no puedes. Sin embargo, lo que puede hacer es usar una clase base abstracta en lugar de una interfaz, y hacer un resumen equals() :

abstract class Command { // put other methods from Command interface here public abstract boolean equals(Object other); public abstract int hashCode(); }

Las subclases de Command deben proporcionar sus propios métodos equals y hashCode.

En general, es una mala práctica obligar a los usuarios de API a extender una clase base, pero puede estar justificado en este caso. Además, si convierte a Command una clase base abstracta en lugar de una interfaz, en lugar de introducir una clase base artificial además de la interfaz Command, no hay riesgo de que los usuarios de la API lo malinterpreten.


Puede crear boolean myEquals() en el interface Command y crear un adaptador de esta manera:

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

Luego solo usa map.put(key, new MyAdapter(command)) lugar de map.put(key, command)


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