Seguramente te has topado con una clase con muchos métodos que tienen el mismo nombre pero diferentes listas de argumentos. Recordará que en esos casos usamos sobrecarga de métodos. Hoy vamos a echar un vistazo a una situación diferente. Imagine que tenemos un método común, pero debería hacer cosas diferentes según la clase en la que se llame. ¿Cómo implementamos este comportamiento? Para entender esto, tomemos la
Animalclase principal, que representa a los animales, y creemos un
speakmétodo en ella:
public class Animal {
public void speak() {
System.out.println("Hello!");
}
}
Aunque recién comenzamos a escribir nuestro programa, probablemente pueda ver un problema potencial: el mundo está lleno de muchos animales, y todos "hablan" de manera diferente: los gatos maúllan, los patos graznan, las serpientes silban, etc. Nuestro objetivo es simple:
nosotros quiero evitar crear un montón de métodos para hablar. En lugar de crear un
meow()método para maullar,
hiss()silbar, etc., queremos que la serpiente silbe, el gato maúlle y el perro ladre cuando
speak()se llame al método. Podemos lograr esto fácilmente usando
la anulación del método . Wikipedia explica el término de la siguiente manera:
Anulación de método, en la programación orientada a objetos, es una característica del lenguaje que permite que una subclase o clase secundaria proporcione una implementación específica de un método que ya proporciona una de sus superclases o clases principales. Eso es básicamente correcto. La anulación le permite tomar algún método de una clase principal y escribir su propia implementación en cada clase derivada. La nueva implementación en la clase secundaria "reemplaza" a la principal. Veamos cómo se ve esto con un ejemplo. Vamos a crear 4 descendientes de nuestra
Animalclase:
public class Bear extends Animal {
@Override
public void speak() {
System.out.println("Growl!");
}
}
public class Cat extends Animal {
@Override
public void speak() {
System.out.println("Meow!");
}
}
public class Dog extends Animal {
@Override
public void speak() {
System.out.println("Woof!");
}
}
public class Snake extends Animal {
@Override
public void speak() {
System.out.println("Hiss!");
}
}
Aquí hay un pequeño truco para el futuro: para anular los métodos de una clase principal, acceda al código de la clase derivada en
IntelliJ IDE , presione
Ctrl+O y seleccione
Anular métodos... en el menú. Acostúmbrate a usar teclas de acceso rápido desde el principio. ¡Acelerarán la codificación! Para obtener el comportamiento deseado, hicimos algunas cosas:
- En cada clase descendiente, creamos un método con el mismo nombre que el método de la clase principal.
-
Le dijimos al compilador que no solo le estamos dando al método el mismo nombre que en la clase principal, sino que queremos anular su comportamiento. Este "mensaje" al compilador se transmite a través de la anotación @Override .
La anotación @Override encima de un método le dice al compilador (así como a otros programadores que leen su código), "No se preocupe. Esto no es un error ni un descuido. Soy consciente de que este método ya existe y quiero anularlo". . - Escribimos la implementación que necesitamos para cada clase descendiente. Cuando
speak()se llama al método, una serpiente debe silbar, un oso debe gruñir, y así sucesivamente.
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
Animal animal3 = new Bear();
Animal animal4 = new Snake();
animal1.speak();
animal2.speak();
animal3.speak();
animal4.speak();
}
}
Salida de la consola: ¡
Woof!
Meow!
Growl!
Hiss!
¡Genial, todo funciona como debería! Creamos 4 variables de referencia cuyo tipo es la
Animalclase padre y les asignamos 4 objetos diferentes de las clases descendientes. Como resultado, cada objeto se comporta de manera diferente. Para cada una de las clases derivadas, el
speak()método anulado reemplaza el método existente
speak()de la
Animalclase (que simplemente muestra "Hablando:" en la consola).
La anulación de métodos tiene varias limitaciones:
-
Un método anulado debe tener los mismos argumentos que el método de la clase principal.
Si el
speakmétodo de la clase padre toma aStringcomo entrada, entonces el método invalidado en la clase descendiente también debe tomar aStringcomo entrada. De lo contrario, el compilador generará un error:public class Animal { public void speak(String s) { System.out.println("Speaking: " + s); } } public class Cat extends Animal { @Override // Error! public void speak() { System.out.println("Meow!"); } } -
El método invalidado debe tener el mismo tipo de valor devuelto que el método de la clase principal.
De lo contrario, obtendremos un error de compilación:
public class Animal { public void speak() { System.out.println("Hello!"); } } public class Cat extends Animal { @Override public String speak() { // Error! System.out.println("Meow!"); return "Meow!"; } } -
El modificador de acceso del método anulado tampoco puede diferir del original:
public class Animal { public void speak() { System.out.println("Hello!"); } } public class Cat extends Animal { @Override private void speak() { // Error! System.out.println("Meow!"); } }
speak()método único para todos en lugar de un montón de métodos diferentes, por ejemplo
bark(),
meow(), etc.
GO TO FULL VERSION