Java Clases Abstractas


En el concepto de la programación orientada a objetos, todos los objetos se describen mediante clases, pero a la inversa, no todas las clases se utilizan para describir objetos. Si una clase no contiene suficiente información para describir un objeto concreto, dicha clase es una clase abstracta.

Además de no poder instanciar objetos, las demás funciones de la clase siguen existiendo. Las variables miembro, los métodos miembro y los constructores mantienen la misma forma de acceso que una clase normal.

Dado que las clases abstractas no pueden instanciar objetos, deben ser heredadas para poder utilizarse. Por esta razón, normalmente se decide si diseñar una clase abstracta en la etapa de diseño.

La clase padre contiene los métodos comunes del conjunto de subclases, pero como la propia clase padre es abstracta, no se pueden utilizar estos métodos.

En Java, una clase abstracta representa una relación de herencia. Una clase solo puede heredar de una clase abstracta, pero puede implementar múltiples interfaces.


Clase abstracta

En el lenguaje Java se utiliza `abstract class` para definir una clase abstracta. Ejemplo:

Código del archivo Employee.java:

/*Nombre de archivo: Employee.java*/ public abstract class Employee { private String name; private String address; private int number; public Employee(String name, String address, int number) { System.out.println("Constructing an Employee"); this.name = name; this.address = address; this.number = number; } public double computePay() { System.out.println("Inside Employee computePay"); return 0.0; } public void mailCheck() { System.out.println("Mailing a check to " + this.name + " " + this.address); } public String toString() { return name + " " + address + " " + number; } public String getName() { return name; } public String getAddress() { return address; } public void setAddress(String newAddress) { address = newAddress; } public int getNumber() { return number; } }

Observa que la clase Employee no tiene nada diferente; aunque es una clase abstracta, todavía tiene 3 variables miembro, 7 métodos miembro y 1 constructor. Ahora si intentas el siguiente ejemplo:

Código del archivo AbstractDemo.java:

/*Nombre de archivo: AbstractDemo.java*/ public class AbstractDemo { public static void main(String [] args) { /*Lo siguiente no está permitido y provocará un error*/ Employee e = new Employee("George W.", "Houston, TX", 43); System.out.println("\n Call mailCheck using Employee reference--"); e.mailCheck(); } }

Cuando intentes compilar la clase AbstractDemo, se producirá el siguiente error:

Employee.java:46: Employee is abstract; cannot be instantiated
      Employee e = new Employee("George W.", "Houston, TX", 43);
                   ^
1 error

Heredar una clase abstracta

Podemos heredar las propiedades de la clase Employee de la siguiente manera:

Código del archivo Salary.java:

/*Nombre de archivo: Salary.java*/ public class Salary extends Employee { private double salary; //Annual salary public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("Within mailCheck of Salary class "); System.out.println("Mailing check to " + getName() + " with salary " + salary); } public double getSalary() { return salary; } public void setSalary(double newSalary) { if(newSalary >= 0.0) { salary = newSalary; } } public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } }

Aunque no podemos instanciar un objeto de la clase Employee, si instanciamos un objeto de la clase Salary, dicho objeto heredará 7 métodos miembro de la clase Employee y, a través de esos métodos, podrá establecer u obtener las tres variables miembro.

Código del archivo AbstractDemo.java:

/*Nombre de archivo: AbstractDemo.java*/ public class AbstractDemo { public static void main(String [] args) { Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00); Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00); System.out.println("Call mailCheck using Salary reference --"); s.mailCheck(); System.out.println("\n Call mailCheck using Employee reference--"); e.mailCheck(); } }

El resultado de compilar y ejecutar el programa anterior es el siguiente:

Constructing an Employee
Constructing an Employee
Call mailCheck using  Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0

Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.

Métodos abstractos

Si deseas diseñar una clase que contenga un método miembro especial cuya implementación concreta sea determinada por sus subclases, entonces puedes declarar dicho método como abstracto en la clase padre.

La palabra clave `Abstract` también se puede utilizar para declarar métodos abstractos. Un método abstracto solo contiene un nombre de método y no tiene cuerpo.

El método abstracto no tiene definición; después del nombre del método va directamente un punto y coma, en lugar de llaves.

public abstract class Employee { private String name; private String address; private int number; public abstract double computePay(); //El resto del código }

Declarar un método abstracto produce los dos resultados siguientes:

  • Si una clase contiene un método abstracto, entonces la clase debe ser abstracta.
  • Cualquier subclase debe sobrescribir el método abstracto de la clase padre, o declararse a sí misma como clase abstracta.

La subclase que herede el método abstracto debe sobrescribirlo. De lo contrario, la subclase también debe declararse como clase abstracta. Finalmente, debe haber una subclase que implemente el método abstracto; de lo contrario, desde la clase padre original hasta la subclase final, ninguna podrá utilizarse para instanciar objetos.

Si la clase Salary hereda de la clase Employee, entonces debe implementar el método `computePay()`:

Código del archivo Salary.java:

/*Nombre de archivo: Salary.java*/ public class Salary extends Employee { private double salary; // Annual salary public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } //El resto del código }

Reglas resumidas de las clases abstractas

  • 1. Las clases abstractas no pueden ser instanciadas (un error muy común entre principiantes); si se instancian, se producirá un error y la compilación fallará. Solo las subclases no abstractas de una clase abstracta pueden crear objetos.

  • 2. Una clase abstracta no necesariamente contiene métodos abstractos, pero una clase con métodos abstractos debe ser abstracta.

  • 3. Los métodos abstractos en una clase abstracta son solo declaraciones, no contienen cuerpo de método, es decir, no proporcionan la implementación concreta del método ni su funcionalidad específica.

  • 4. Los constructores y los métodos de clase (métodos modificados con `static`) no pueden declararse como métodos abstractos.

  • 5. Las subclases de una clase abstracta deben proporcionar la implementación concreta de los métodos abstractos de la clase abstracta, a menos que la subclase también sea abstracta.

Otras extensiones