¿Cuándo utiliza la anotación @Override de Java y por qué?

498

¿Cuáles son las mejores prácticas para usar la @Overrideanotación de Java y por qué?

Parece que sería excesivo marcar cada método anulado con la @Overrideanotación. ¿Existen ciertas situaciones de programación que requieren el uso de @Overridey otras que nunca deberían usar el @Override?

Alex B
fuente

Respuestas:

515

Úselo cada vez que anule un método para obtener dos beneficios. Hágalo para que pueda aprovechar la comprobación del compilador para asegurarse de que realmente está anulando un método cuando cree que lo está haciendo. De esta manera, si comete un error común de escribir mal el nombre de un método o no coincide correctamente con los parámetros, se le advertirá que su método no se anula realmente como cree. En segundo lugar, hace que su código sea más fácil de entender porque es más obvio cuando se sobrescriben los métodos.

Además, en Java 1.6 puede usarlo para marcar cuándo un método implementa una interfaz para obtener los mismos beneficios. Creo que sería mejor tener una anotación separada (como @Implements), pero es mejor que nada.

Dave L.
fuente
44
En la misma línea que "más fácil de entender", los IDEs detectarán la anotación @Override y marcarán visualmente el método de anulación en el editor.
Bob Cross
47
Algunos IDE marcarán un método anulado al que también le falta la anotación @Override.
Jay R.
20
El otro beneficio es que si la clase principal cambia, el compilador se asegurará de que las clases secundarias también se hayan actualizado.
David
44
@ Jay R .: Cierto. De hecho, por ejemplo, Eclipse puede incluso agregar automáticamente el @Override si falta.
sleske
32
En caso de que alguien más haya llegado aquí debido al cambio aparentemente indocumentado de 1.5 a 1.6 para @Overrides en métodos que provienen de interfaces, bugs.sun.com/bugdatabase/view_bug.do?bug_id=5008260 parece ser el error correspondiente. (¡Gracias por señalarlo, Dave L.!)
Henrik Heimbuerger el
110

Creo que es más útil como recordatorio en tiempo de compilación de que la intención del método es anular un método principal. Como ejemplo:

protected boolean displaySensitiveInformation() {
  return false;
}

A menudo verá algo como el método anterior que anula un método en la clase base. Este es un detalle de implementación importante de esta clase: no queremos que se muestre información confidencial.

Supongamos que este método se cambia en la clase padre a

protected boolean displaySensitiveInformation(Context context) {
  return true;
}

Este cambio no provocará errores o advertencias en tiempo de compilación, pero cambia por completo el comportamiento previsto de la subclase.

Para responder a su pregunta: debe usar la anotación @Override si la falta de un método con la misma firma en una superclase es indicativo de un error.

jon
fuente
46

Aquí hay muchas buenas respuestas, así que permítanme ofrecerles otra forma de verlo ...

No hay exageración cuando estás codificando. No le cuesta nada escribir @override, pero los ahorros pueden ser inmensos si escribe mal el nombre de un método o se equivocó un poco en la firma.

Piénsalo de esta manera: en el tiempo que navegaste aquí y escribiste esta publicación, prácticamente utilizaste más tiempo del que pasarías escribiendo @override por el resto de tu vida; pero un error que evita puede ahorrarle horas.

Java hace todo lo posible para asegurarse de que no cometió ningún error en el tiempo de edición / compilación, esta es una forma prácticamente gratuita de resolver una clase completa de errores que no se pueden evitar de ninguna otra manera fuera de las pruebas exhaustivas.

¿Podría encontrar un mejor mecanismo en Java para asegurarse de que cuando el usuario intenta anular un método, realmente lo hizo?

Otro efecto positivo es que si no proporciona la anotación, le advertirá en el momento de la compilación que anuló accidentalmente un método principal, algo que podría ser significativo si no tuviera la intención de hacerlo.

Bill K
fuente
3
"No hay exageración cuando estás codificando". Estoy de acuerdo con esto, es por eso que encuentro que los langs dinámicos son tan incorrectos (aunque el 100% de mi trabajo remunerado está en rubí en este momento).
Dan Rosenstark
44
+1: He tenido, tal vez, 10 errores causados ​​por un error en la anulación: el tiempo requerido para encontrar cualquiera de ellos habría excedido fácilmente el tiempo para escribir @Override en cada uno de mis métodos de anulación. Además, si @Override es algo oneroso, probablemente esté usando la herencia en exceso.
Lawrence Dol
77
Una desventaja muy real es que hace que el código sea más difícil de leer al llenarlo de caracoles. Quizás esto sea culpa de mi IDE, pero lo he experimentado yo mismo.
trata bien tus modificaciones el
99
@phyzome Si encuentra engorrosos los "Caracoles", no está utilizando CUALQUIER LUGAR CERCA de suficientes comentarios. Deberían ser solo una línea sobre el encabezado de su método, que debería ser casi tan grande como su método en la mayoría de los casos (unas pocas líneas) para proporcionar texto de desplazamiento y javadocs decentes. Supongo que estoy diciendo que el problema no son los caracoles, son tus hábitos de lectura. ¿Te molestan todos esos paréntesis en el código?
Bill K
44
Sí, hay una exageración en la codificación: cuando escribes comentarios que simplemente repiten lo que obviamente hace el código.
Hormigas
22

Yo siempre uso la etiqueta. Es un indicador de tiempo de compilación simple para detectar pequeños errores que podría cometer.

Atrapará cosas como en tostring()lugar detoString()

Las pequeñas cosas ayudan en grandes proyectos.

jjnguy
fuente
18

El uso de la @Overrideanotación actúa como una protección en tiempo de compilación contra un error de programación común. Lanzará un error de compilación si tiene la anotación en un método que realmente no está anulando el método de superclase.

El caso más común en el que esto es útil es cuando está cambiando un método en la clase base para tener una lista de parámetros diferente. Un método en una subclase que solía anular el método de la superclase ya no lo hará debido a la firma del método modificado. Esto a veces puede causar un comportamiento extraño e inesperado, especialmente cuando se trata de estructuras de herencia complejas. La @Overrideanotación protege contra esto.

toluju
fuente
La mejor respuesta. Corto y dulce. Me gustaría que pudieras explicar cómo funciona la "salvaguardia" ... nadie ha explicado esto.
djangofan el
Es simple de explicar. Si comete un error (ya sea cambiando la interfaz, la clase abstracta o la subclase, recibirá una advertencia (como en Eclipse) o un error en tiempo de compilación que le indica que su @Override no está funcionando. El error real el mensaje dependerá de lo que se haya cambiado, pero en Eclipse (por ejemplo) queda muy claro muy rápidamente que hay un problema: verá ese pequeño subrayado en zigzag rojo y un cursor sobre el texto ofensivo le dirá qué está mal. A eso lo llamo Good Value.
Ichiro Furusato
14

Para aprovechar la verificación del compilador, siempre debe usar la anulación de anulación. Pero no olvide que Java Compiler 1.5 no permitirá esta anotación al anular los métodos de interfaz. Solo puede usarlo para anular los métodos de clase (abstractos o no).

Algunos IDE, como Eclipse, incluso configurados con Java 1.6 runtime o superior, mantienen el cumplimiento con Java 1.5 y no permiten el uso @override como se describe anteriormente. Para evitar ese comportamiento, debe ir a: Propiedades del proyecto -> Compilador Java -> Marque “Habilitar configuraciones específicas del proyecto” -> Elija “Nivel de cumplimiento del compilador” = 6.0 o superior.

Me gusta usar esta anotación cada vez que anulo un método de forma independiente, si la base es una interfaz o clase.

Esto le ayuda a evitar algunos errores típicos, como cuando piensa que está anulando un controlador de eventos y luego no ve que sucede nada. Imagine que desea agregar un detector de eventos a algún componente de la interfaz de usuario:

someUIComponent.addMouseListener(new MouseAdapter(){
  public void mouseEntered() {
     ...do something...
  }
});

El código anterior se compila y se ejecuta, pero si mueve el mouse dentro de algún componente UIC, el código "hacer algo" indicará ejecutar, porque en realidad no está anulando el método base mouseEntered(MouseEvent ev). Simplemente crea un nuevo método sin parámetros mouseEntered(). En lugar de ese código, si ha utilizado la @Overrideanotación, ha visto un error de compilación y no ha perdido el tiempo pensando por qué su controlador de eventos no se estaba ejecutando.

Compañeros de Donal
fuente
8

@Override en la implementación de la interfaz es inconsistente ya que no existe tal cosa como "anular una interfaz" en Java.

@Override en la implementación de la interfaz es inútil ya que en la práctica no detecta errores que la compilación no detectaría de todos modos. Solo hay un escenario descabellado en el que la anulación de los implementadores realmente hace algo: si implementa una interfaz y la interfaz ELIMINA los métodos, se le notificará en tiempo de compilación que debe eliminar las implementaciones no utilizadas. Tenga en cuenta que si la nueva versión de la interfaz tiene métodos NUEVOS o CAMBIADOS, obviamente obtendrá un error de compilación de todos modos ya que no está implementando las nuevas cosas.

@Override en implementadores de interfaz nunca debería haberse permitido en 1.6, y con eclipse lamentablemente eligiendo insertar automáticamente las anotaciones como comportamiento predeterminado, obtenemos muchos archivos fuente desordenados. Al leer el código 1.6, no puede ver en la anotación @Override si un método realmente anula un método en la superclase o simplemente implementa una interfaz.

Usar @Override cuando realmente anula un método en una superclase está bien.

Runa
fuente
2
Hay diferentes opiniones sobre ese punto. Ver stackoverflow.com/questions/212614/… .
sleske
8

Es mejor usarlo para todos los métodos destinados a anulación, y Java 6+, todos los métodos destinados a la implementación de una interfaz.

Primero, detecta errores ortográficos como " hashcode()" en lugar de " hashCode()" en tiempo de compilación. Puede ser desconcertante depurar por qué el resultado de su método no parece coincidir con su código cuando la verdadera causa es que su código nunca se invoca.

Además, si una superclase cambia la firma de un método, las anulaciones de la firma anterior pueden quedar "huérfanas" y quedar como código muerto confuso. La @Overrideanotación lo ayudará a identificar a estos huérfanos para que puedan modificarse para que coincidan con la nueva firma.

erickson
fuente
7

Si te encuentras anulando métodos (no abstractos) muy a menudo, probablemente quieras echar un vistazo a tu diseño. Es muy útil cuando el compilador no detectaría el error. Por ejemplo, tratar de anular initValue () en ThreadLocal, lo que he hecho.

Usar @Override al implementar métodos de interfaz (función 1.6+) me parece un poco exagerado. Si tiene muchos métodos, algunos de los cuales anulan y otros no, ese probablemente sea un mal diseño nuevamente (y su editor probablemente mostrará cuál es cuál si no lo sabe).

Tom Hawtin - tackline
fuente
2
En realidad, también es bueno para los métodos de interfaz anulados. Si, por ejemplo, elimino un método antiguo y obsoleto de una interfaz, ese método también debería eliminarse de todas las clases de implementación; es fácil detectarlas si usan @override.
Dominik Sandjaja
7

@Override en las interfaces en realidad son útiles, porque recibirá advertencias si cambia la interfaz.

Asgeir S. Nilsen
fuente
7

Otra cosa que hace es que al leer el código es más obvio que está cambiando el comportamiento de la clase principal. Que puede ayudar en la depuración.

Además, en el libro de Joshua Block, Effective Java (2nd edition), el ítem 36 brinda más detalles sobre los beneficios de la anotación.

Diastrofismo
fuente
Sí, de hecho - artículo 36 :)
Chris Kimpton
6

No tiene ningún sentido usar @Override al implementar un método de interfaz. No hay ninguna ventaja en usarlo en ese caso: el compilador ya detectará su error, por lo que es un desorden innecesario.

Steve R.
fuente
66
El uso @Overrideen una interfaz lo obligará a notar cuándo se elimina un método en la interfaz.
Alex B
@Alex: Eliminar métodos en una interfaz es un cambio radical, como agregarlos. Una vez que se publica una interfaz, se bloquea de manera efectiva a menos que tenga un control completo sobre todo el código que la usa.
Lawrence Dol
6

Cada vez que un método anula otro método, o un método implementa una firma en una interfaz.

La @Overrideanotación le asegura que de hecho anuló algo. Sin la anotación, corre el riesgo de una falta de ortografía o una diferencia en los tipos y números de parámetros.

Greg Mattes
fuente
1
Solo puede usarlo para marcar la implementación de la interfaz en Java 1.6
Dave L.
5

Lo uso todo el tiempo. Es más información que puedo usar para descubrir rápidamente lo que sucede cuando reviso el código en un año y he olvidado lo que estaba pensando la primera vez.

Hank Gay
fuente
5

Lo mejor es usarlo siempre (o hacer que el IDE lo complete por usted)

La utilidad de @Override es detectar cambios en las clases principales que no se han informado en la jerarquía. Sin él, puede cambiar la firma de un método y olvidar alterar sus anulaciones, con @Override, el compilador lo detectará por usted.

Ese tipo de red de seguridad siempre es bueno tener.


fuente
1
Entonces, si cambia el método principal y no usa @Override en el método de la clase secundaria, ¿la compilación dirá algo o permanecerá en silencio? ¿El uso de "Anulación" le dará más información y, de ser así, qué?
djangofan el
5

Lo uso en todas partes. Sobre el tema del esfuerzo por marcar métodos, dejé que Eclipse lo haga por mí, así que no es un esfuerzo adicional.

Soy religioso con respecto a la refactorización continua ... por lo tanto, usaré cada pequeña cosa para que funcione mejor.

willCode4Beer
fuente
5
  • Usado solo en declaraciones de métodos.
  • Indica que la declaración del método anotado anula una declaración en supertipo.

Si se usa de manera consistente, lo protege de una gran clase de errores nefastos.

Use la anotación @Override para evitar estos errores: (Detecte el error en el siguiente código :)

public class Bigram {
    private final char first;
    private final char second;
    public Bigram(char first, char second) {
        this.first  = first;
        this.second = second;
    }
    public boolean equals(Bigram b) {
        return b.first == first && b.second == second;
    }
    public int hashCode() {
        return 31 * first + second;
    }

    public static void main(String[] args) {
        Set<Bigram> s = new HashSet<Bigram>();
        for (int i = 0; i < 10; i++)
            for (char ch = 'a'; ch <= 'z'; ch++)
                s.add(new Bigram(ch, ch));
        System.out.println(s.size());
    }
}

fuente: Java efectivo

jai
fuente
No sé cuáles son las reglas de precedencia del operador en Java, pero su método de igualdad es gritar ¡BUUUUUUUUUUUG! Escribiría (b.first == first) && (b.second == second), incluso si &&tuviera menor prioridad que ==.
pyon 02 de
¿Sabía que su enlace muestra un mensaje de "debe suscribirse" que cubre la parte útil de esa página?
Adriano Varoli Piazza
@Adriano: ¡Lo siento amigo! Estoy indefenso !! Cuando escribí la 'respuesta', estaba disponible. No te preocupes ... compra el libro. ¡Vale la pena tenerlo!
jai
55
El método igual no anula: el original Object::equalses boolean equals(Object), mientras que el anulado equalses boolean equals(Bigram), que tiene una firma de método diferente, que no anula. Agregar @Override al equalsdetectará este error.
Ming-Tang
3

Tenga cuidado cuando use Override, porque no puede hacer ingeniería inversa en starUML después; hacer la uml primero.

Horatiu Jeflea
fuente
2

Parece que la sabiduría aquí está cambiando. Hoy instalé IntelliJ IDEA 9 y noté que su " falta de inspección @Override " ahora capta no solo los métodos abstractos implementados, sino también los métodos de interfaz implementados. En la base de código de mi empleador y en mis propios proyectos, siempre he tenido la costumbre de usar @Override para los métodos abstractos implementados anteriormente. Sin embargo, al repensar el hábito, queda claro el mérito de usar las anotaciones en ambos casos. A pesar de ser más detallado, protege contra la clase base frágil problema de la (no tan grave como los ejemplos relacionados con C ++) donde el nombre del método de interfaz cambia, dejando huérfano al posible método de implementación en una clase derivada.

Por supuesto, este escenario es principalmente una hipérbole; la clase derivada ya no se compilaría, ahora carece de una implementación del método de interfaz renombrado, y hoy probablemente se usaría un Método de cambio de nombre operación de refactorización del para abordar la base de código completa en masa.

Dado que la inspección de IDEA no es configurable para ignorar los métodos de interfaz implementados, hoy cambiaré tanto mi hábito como los criterios de revisión de código de mi equipo.

seh
fuente
2

La anotación @Override se usa para ayudar a verificar si el desarrollador debe anular el método correcto en la clase o interfaz principal. Cuando el nombre de los métodos de super cambia, el compilador puede notificar ese caso, que es solo para mantener la coherencia con el super y la subclase.

Por cierto, si no anunciamos la anotación @Override en la subclase, pero anulamos algunos métodos de la super, entonces la función puede funcionar como esa con la @Override. Pero este método no puede notificar al desarrollador cuando se cambió el método del super. ¿Porque no conocía el propósito del desarrollador: anular el método de super o definir un nuevo método?

Entonces, cuando queremos anular ese método para hacer uso del Polimorfismo, es mejor agregar @Override sobre el método.

lzlstyle
fuente
1

Lo uso todo lo que puedo para identificar cuándo se anula un método. Si observa el lenguaje de programación Scala, también tienen una palabra clave de anulación. Me parece útil

Berlin Brown
fuente
0

Le permite (bueno, el compilador) detectar cuando ha usado la ortografía incorrecta en un nombre de método que está anulando.

JeeBee
fuente
0

La anulación de anulación se utiliza para aprovechar el compilador, para verificar si realmente está anulando un método de la clase principal. Se utiliza para notificar si comete algún error, como error de escribir mal el nombre de un método, error de no coincidir correctamente los parámetros

Siva
fuente
0

Creo que es mejor codificar el @override siempre que esté permitido. Ayuda para la codificación. sin embargo, debe tenerse en cuenta que para ecipse Helios, ya sea sdk 5 o 6, se permite la anotación @override para los métodos de interfaz implementados. En cuanto a Galileo, ya sea 5 o 6, no se permite la anulación de anulación.

lwpro2
fuente
0

Las anotaciones proporcionan metadatos sobre el código al Compilador y la anotación @Override se usa en caso de herencia cuando anulamos cualquier método de clase base. Simplemente le dice al compilador que está anulando el método. Puede evitar algunos tipos de errores comunes que podemos hacer, como no seguir la firma adecuada del método o escribir mal en el nombre del método, etc. Por lo tanto, es una buena práctica utilizar la anotación @Override.

gprathour
fuente
0

Para mí, @Override me asegura que tengo la firma del método correcta. Si pongo la anotación y el método no está escrito correctamente, entonces el compilador se queja dejándome saber que algo está mal.

Valle
fuente
0

Simple: cuando desee anular un método presente en su superclase, use la @Overrideanotación para hacer una anulación correcta. El compilador le avisará si no lo anula correctamente.

Sree
fuente