"¡Hola, amigo! Tenemos un nuevo tema fascinante".

"¡Hoy es solo un día de temas fascinantes!"

"¡Por que gracias!"

"De nada."

"¿Recuerdas cuando introdujimos la clase base ChessItem para simplificar todas las clases de piezas de ajedrez?"

"Sí."

"Ahora imagina que cada pieza tiene un método que maneja la representación de la pieza en la pantalla. Llamas al método y la pieza se dibuja a sí misma en sus coordenadas actuales. ¿Sería útil mover este método a la clase base?"

"Sí." Una vez que haya aprendido sobre el polimorfismo, podría llamar al método de renderizado para todas las piezas, independientemente de su tipo. Algo como esto:"

Por ejemplo:
class ChessBoard
{
  public void drawAllChessItems()
  {
  //draw them regardless of their type.
  ArrayList <ChessItem> items = new ArrayList<ChessItem>();
  items.add(new King());
  items.add(new Queen());
  items.add(new Bishop());

  //draw them regardless of their type.
  for (ChessItem item: items)
  {
   item.draw();
  }
 }
}

"Bien hecho. Exactamente. ¿Y qué haría el método de sorteo de la clase ChessItem en sí misma?"

"No lo sé. El ajedrez no tiene esa pieza. Y eso significa que no tiene representación visual".

"Precisamente. Y no tiene sentido crear un objeto ChessItem. No existe tal pieza de ajedrez. Es solo una abstracción , una clase que creamos por conveniencia. Así es como funciona la abstracción en OOP: movimos todo lo importante (compartido) por todas las piezas) datos y métodos en una clase base , pero mantuvimos sus diferencias en las clases correspondientes a piezas de ajedrez específicas".

Java tiene un tipo de clase especial para esto: la clase abstracta . Aquí hay tres cosas para recordar acerca de las clases abstractas.

1) Una clase abstracta puede declarar métodos sin implementarlos. Tal método se llama método abstracto.

Por ejemplo:
 public abstract class ChessItem
{
 public int x, y; //coordinates
 private int value; //the piece's "value"

 public int getValue() //an ordinary method, returns value
 {
   return value;
 }

 public abstract void draw(); //abstract method. There is no implementation.

}

2) Un método abstracto está marcado con la palabra clave abstract .

Si una clase tiene incluso un método abstracto, entonces la clase también se marca con abstract .

3) No puedes crear objetos de una clase abstracta. El código que intenta hacerlo simplemente no se compilará.

codigo Java Descripción
ChessItem item = new ChessItem();
item.draw();
Este código no compilará.
ChessItem item = new Queen();
item.draw();
Pero puedes hacer esto.

4) Si su clase hereda una clase abstracta, debe anular todos los métodos abstractos heredados, es decir, debe implementarlos. De lo contrario, su clase también deberá declararse abstracta. Si la clase tiene incluso un método no implementado declarado directamente en la clase o heredado de la clase principal, entonces la clase se considera abstracta.

"Pero, ¿por qué es necesario todo esto? ¿Por qué necesitamos clases abstractas? ¿No es posible usar clases ordinarias en su lugar? Y en lugar de métodos abstractos, ¿no podemos simplemente crear implementaciones vacías que consisten en abrir y cerrar corchetes?"

"Podrías. Pero estas restricciones son como el privatemodificador. Usamos el privatemodificador para bloquear deliberadamente el acceso directo a los datos, para que otros programadores y sus clases usen nuestros publicmétodos".

Lo mismo se aplica a una clase abstracta. Quien haya escrito la clase no quiere que nadie cree instancias de la clase. Por el contrario, el autor espera que los métodos abstractos de su clase abstracta sean heredados y anulados.

"Todavía no entiendo por qué querríamos complicarnos la vida de esta manera".

"La ventaja de esta característica es evidente en proyectos grandes. Cuantas más clases tenga, más claramente necesitará delinear sus roles. Verá la ventaja de hacer esto, y pronto. Todo el mundo tiene que pasar por esto".