JavaRush /Blog Java /Random-ES /Clases abstractas en Java con ejemplos específicos.

Clases abstractas en Java con ejemplos específicos.

Publicado en el grupo Random-ES
¡Hola! En conferencias anteriores nos familiarizamos con las interfaces y descubrimos para qué sirven. El tema de hoy tendrá algo en común con el anterior. Hablemos de clases abstractas en Java. Clases abstractas en Java con ejemplos concretos - 1

¿Por qué las clases se llaman "abstractas"?

Probablemente recuerdes qué es la "abstracción"; ya lo hemos cubierto :) Si de repente lo olvidaste, está bien, recordemos: este es el principio de la programación orientada a objetos , según el cual al diseñar clases y crear objetos, es necesario resaltar sólo las propiedades principales de una entidad y descartar las secundarias. Por ejemplo, si estamos diseñando una clase SchoolTeacher(un maestro de escuela), es poco probable que necesitemos la característica " altura ". En efecto: para un profesor esta característica no es importante. Pero si creamos una clase en el programa BasketballPlayer, un jugador de baloncesto, la altura se convertirá en una de las características principales. Entonces, una clase abstracta es el “espacio en blanco” más abstracto y aproximado para un grupo de clases futuras. Esta preparación no se puede utilizar en su forma terminada, está demasiado "cruda". Pero describe un cierto estado general y comportamiento que tendrán las clases futuras, herederas de la clase abstracta.

Ejemplos de clases abstractas de Java

Veamos un ejemplo sencillo con coches:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
Así es como se ve la clase abstracta más simple. Como puedes ver, nada especial :) ¿Para qué podríamos necesitarlo? En primer lugar, describe de la forma más abstracta posible la entidad que necesitamos: un coche. La palabra resumen está aquí por una razón. No existen “sólo máquinas” en el mundo. Hay camionetas, autos de carreras, sedanes, cupés, SUV. Nuestra clase abstracta es simplemente un "modelo" a partir del cual luego crearemos clases de automóviles.
public class Sedan extends Car {

   @Override
   public void gas() {
       System.out.println("¡El sedán acelera!");
   }

   @Override
   public void brake() {
       System.out.println("¡El sedán reduce la velocidad!");
   }

}
Esto se parece mucho a lo que hablamos en las conferencias sobre herencia. Sólo que ahí teníamos una clase Cary sus métodos que no eran abstractos. Pero esta solución tiene una serie de desventajas que se corrigen en clases abstractas. En primer lugar, no se puede crear una instancia de una clase abstracta:
public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // ¡Error! ¡La clase Car es abstracta!
   }
}
Este "truco" fue implementado específicamente por los creadores de Java. Una vez más, solo para recordar: una clase abstracta es solo un modelo para futuras clases "normales" . No necesitas copias del dibujo, ¿verdad? Entonces no hay necesidad de crear instancias de una clase abstracta :) Y si la clase Carno fuera abstracta, podríamos crear fácilmente sus objetos:
public class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       // algo de logica
   }

   public  void brake() {
       // algo de logica
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Todo está bien, la máquina ha sido creada
   }
}
Ahora tenemos algún tipo de automóvil extraño en nuestro programa: ni un camión, ni un auto de carreras, ni un sedán, sino algo en general. Ese mismo “sólo una máquina” que no existe en la naturaleza. El mismo ejemplo se puede dar con los animales. Imagínese si aparecieran objetos en su programa Animal: " solo un animal ". De qué tipo es, a qué familia pertenece, qué características tiene, no está claro. Sería extraño verlo en el programa. No existen “sólo animales” en la naturaleza. Sólo perros, gatos, zorros, topos y otros. Las clases abstractas nos liberan de los “ solo objetos ”. Nos dan un estado y un comportamiento básicos. Por ejemplo, todos los coches deben tener un modelo , color y velocidad máxima , y ​​también deben poder acelerar y frenar . Eso es todo. Este es un esquema abstracto general, luego usted mismo diseña las clases que necesita. Tenga en cuenta: dos métodos en una clase abstracta también se designan como abstractos y no se implementan en absoluto. La razón es la misma: las clases abstractas no crean un "comportamiento predeterminado" para "simples máquinas". Simplemente dicen que deberían poder fabricar todos los coches. Sin embargo, si aún necesita el comportamiento predeterminado, puede implementar métodos en una clase abstracta. Java no prohíbe esto:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       System.out.println("¡Vamos!");
   }

   public abstract void brake();

   //getters y setters
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println("¡El sedán reduce la velocidad!");
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
Salida de la consola: "¡Acelera!" Como puede ver, implementamos un método en la clase abstracta, pero no implementamos el segundo. Como resultado, el comportamiento de nuestra clase Sedanse dividió en dos partes: si llama a un método en ella gas(), se “tirará” de la clase abstracta principal Cary brake()redefinimos el método en la clase Sedan. Resultó muy conveniente y flexible. ¿Pero ahora nuestra clase no es tan abstracta ? Después de todo, de hecho, la mitad de sus métodos están implementados. De hecho (y ésta es una característica muy importante) una clase es abstracta si al menos uno de sus métodos es abstracto . Al menos uno de dos, al menos uno de mil métodos, no importa. Incluso podemos implementar todos los métodos y no dejar ninguno abstracto. Habrá una clase abstracta sin métodos abstractos. En principio, esto es posible y el compilador no producirá errores, pero es mejor no hacer esto: la palabra resumen perderá su significado y sus compañeros programadores se sorprenderán mucho al ver esto :/ Además, si un método está marcado con la palabra abstracto, cada clase descendiente debe implementar o declararse abstracta. De lo contrario, el compilador arrojará un error . Por supuesto, cada clase puede heredar sólo de una clase abstracta, por lo que en términos de herencia no hay diferencia entre clases abstractas y regulares. No importa si heredamos de una clase abstracta o de una normal, sólo puede haber una clase padre.

¿Por qué no existe herencia de clases múltiples en Java?

Ya hemos dicho que no existe herencia múltiple en Java, pero no hemos descubierto realmente por qué. Probemos esto ahora. El punto es que si Java tuviera herencia múltiple, las clases hijas no podrían decidir qué comportamiento elegir. Digamos que tenemos dos clases Tostery NuclearBomb:
public class Toster {


 public void on() {

       System.out.println("¡La tostadora está encendida, la tostada se está preparando!");
   }

   public void off() {

       System.out.println("¡La tostadora está apagada!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Взрыв!");
   }
}
Como puedes ver, ambos tienen un método on(). En el caso de una tostadora, empieza a cocinar tostadas, y en el caso de una bomba nuclear, provoca una explosión. Oh :/ Ahora imagina que decides (¡no sé por qué de repente!) crear algo intermedio. ¡ Y aquí está tu clase MysteriousDevice! Este código, por supuesto, no funciona, y lo presentamos simplemente como un ejemplo de “cómo podría ser”:
public class MysteriousDevice extends Toster, NuclearBomb {

   public static void main(String[] args) {

       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // ¿Y qué debería pasar aquí? ¿Obtendremos un brindis o un apocalipsis nuclear?
   }
}
Veamos qué tenemos. El misterioso dispositivo proviene tanto de la Tostadora como de la Bomba Nuclear. Ambos tienen un método on()y, como resultado, no está claro qué método on()debería activarse en el objeto MysteriousDevicesi lo llamamos. El objeto no podrá entender esto. Pues como guinda del pastel: la Bomba Nuclear no tiene método off(), por lo que si adivinamos mal, no habrá forma de apagar el dispositivo. Clases abstractas en Java con ejemplos concretos - 2 Es precisamente debido a esta confusión, cuando un objeto no está claro qué comportamiento debe elegir, que los creadores de Java abandonaron la herencia múltiple. Sin embargo, recuerde que las clases de Java implementan muchas interfaces. Por cierto, ¡ya has encontrado al menos una clase abstracta en tus estudios! Aunque tal vez no me di cuenta :)
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
Esta es tu vieja clase de amigos Calendar. Es abstracto y tiene varios herederos. Uno de ellos es GregorianCalendar. Ya lo usaste en lecciones sobre fechas :) Todo parece estar claro, solo queda un punto: ¿cuál es la diferencia fundamental entre clases abstractas e interfaces ? ¿Por qué agregaron ambos a Java y no se limitaron a uno solo? Esto bien podría ser suficiente. ¡Hablaremos de esto en la próxima conferencia! Nos vemos:)
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION