java annotations override language-design method-signature

java - ¿Qué es "anulación-equivalencia" y cómo se relaciona con @Override?



annotations language-design (2)

Leyendo el Javadoc para la anotación @Override , encontré la siguiente regla:

Si se anota un método con este tipo de anotación, los compiladores deben generar un mensaje de error a menos que se cumpla al menos una de las siguientes condiciones:

  • El método anula o implementa un método declarado en un supertipo.
  • El método tiene una firma que es anulada equivalente a la de cualquier método público declarado en Object.

Estoy claro en el primer punto, pero no estoy seguro sobre el segundo punto.

¿Qué significa "anular el equivalente"? ¿Cómo son los métodos públicos de Object especiales a este respecto? ¿Y por qué esto no está cubierto bajo el primer criterio?

Nota de actualización: Esto solo se aplica a la documentación de Java 7. El documento de Java 6 no dice nada acerca de anular la equivalencia. ¿Por qué el cambio?

Actualizar:

Después de consultar el JLS ( Sección 8.4.2 ), encontré la siguiente explicación de anulación-equivalencia:

La firma de un método m1 es una subscripción de la firma de un método m2 si:

  • m2 tiene la misma firma que m1 , o
  • La firma de m1 es la misma que el borrado ( §4.6 ) de la firma de m2 .

Dos firmas de método m1 y m2 son equivalentes a la anulación si m1 es una subsignatura de m2 o m2 es una suscripción de m1 .

Por lo que puedo decir, esto responde a la primera pregunta ("¿Qué significa?") Y la tercera pregunta ("¿Por qué la primera condición no cubre esto?").

Si comprendo correctamente (¡infórmeme si no lo hago!), Solo hay un caso en el que dos métodos son equivalentes a los de anulación y que no están incluidos en la primera condición de la pregunta original. Este es el caso cuando la eliminación de la firma del método de subclase es la misma que la firma del método de superclase, pero no al revés.

La segunda condición de la pregunta original, entonces, solo entraría en juego cuando intentemos agregar parámetros de tipo al intentar "anular" un método público de la clase Object . Probé el siguiente ejemplo simple para probar esto, con un parámetro de tipo no utilizado:

public class Foo { @Override public <T> boolean equals(Object obj) { return true; } }

Por supuesto, esta clase no se compila, porque el método en realidad no reemplaza al método equals y, por lo tanto, choca con él. Pero también recibo un error por usar la anotación @Override . ¿Me equivoco al suponer que este es un ejemplo válido de la segunda condición para el uso de @Override ? ¿O el compilador está generando este error a pesar de no ser requerido ?


El motivo de esto es permitirle utilizar la anotación @Override en las interfaces, que no heredan de Object pero declaran implícitamente todos los métodos públicos de Object (consulte la sección JLS, sección 9.2, miembros de la interfaz ). Por lo tanto, se le permite declarar una interfaz como:

interface Bar { @Override int hashCode(); }

Sin embargo, no se le permitiría declarar la siguiente interfaz:

interface Quux { @Override Object clone(); }

ya que el método clone() no se declara implícitamente en una interfaz (no es public ).

Esto se describe en la sección 9.6.3.4 de JLS, en @verdencia (el Javadoc para @Override aún se refiere a un número de sección antiguo)


Su pregunta es básicamente una pregunta de diseño y JLS explica su:

"La noción de subscripción está diseñada para expresar una relación entre dos métodos cuyas firmas no son idénticas, pero en las cuales uno puede anular el otro. Específicamente, permite que un método cuya firma no use tipos genéricos anule cualquier versión generada de ese método. Esto es importante para que los diseñadores de bibliotecas puedan generar libremente métodos independientemente de los clientes que definen subclases o subinterfaces de la biblioteca ".

Su código no es un ejemplo válido de esto, vea el siguiente código que funciona:

public class SubSignatureTest extends SignatureTest { @Override public List test(Collection p) { return null; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub } } class SignatureTest { public <T> List<T> test(Collection<T> t) { return null; } }

Todo el punto es que la firma de superclase y la subclase deben ser iguales después del borrado.

EDITAR: Cuando hablamos de anulación de equivalencia, la clase padre debe tener un método genérico y la clase hija debe tener un método no genérico. Aquí hay un ejemplo para explicar esto. El código siguiente no funcionará porque la clase secundaria tiene un método genérico. Por un momento, asumamos que Java permitió que la llamada en el método principal siempre falle:

class A{ public int compareTo(Object o){ return 0; } } class B extends A implements Comparable<B>{ public int compareTo(B b){ return 0; } public static void main(String[] argv){ System.out.println(new B().compareTo(new Object())); } }

En la clase B el método será así después de la compilación:

public int compareTo(Object x){ return compareTo((B)x); }

Lo que significa que esto siempre es un error: new B().compareTo(new Object()) . Por lo tanto, Java no permitirá que la clase secundaria tenga un método genérico si la clase principal tiene un método no genérico. Por lo tanto, no puede definir los métodos de equivalencia de anulación para la clase de objeto.

Espero que se aclare.

Usé la publicación http://lists.seas.upenn.edu/pipermail/types-list/2006/001091.html como referencia, tiene muchos más detalles.