¿Qué son las clases abstractas en Java?


Trabajando con clases abstractas en JDeveloper 11g

Una clase es abstracta si al menos contiene un método declarado como abstracto usando el modificador abstract. Los métodos declarados como abstractos no implementan código y difieren la implementación del código a otra clase.

Tabla de contenido

  • ¿Qué son las clases abstractas en Java?
  • Formas de diferir código Java
  • Características de una clase abstracta.
  • ¿Cuándo utilizar clases abstractas?
  • Para saber más sobre los diagramas Java de Oracle visitar los siguientes sitios
  • Para saber más sobre los diagramas UML.org visitar los siguientes sitios
  • ¿Qué son las interfaces en Java?
  • Relación entre una clase y una interfaz
  • En Java hay tres tipos de relaciones:
  • Heredar clases abstractas
  • Tres situaciones de heredar clases abstractas
  • Situación 1 - Se crearán instancias de la clase padre, superclase o abstracta
  • Situación 2 - Se crearán instancias de la clase  padre, superclase o abstracta pero usando los constructores de los hijos, subclases
  • Situación 3 - Se crearán instancias de los hijos, subclases

Formas de diferir código Java

Hay dos formas de diferir código de una clase abstracta a otra clase:
  • Forma 1 - Cuando se crea una referencia de objeto de una clase abstracta y se instancia usando el operador new
  • Forma 2 - Cuando se hereda una clase abstracta usando la palabra clave extends

Características de una clase abstracta.

  • Si una clase abstracta es instanciada el compilador dará un error de sintaxis, el compilador dejará de dar un error cuando la clase que crea la instancia de la clase abstracta sobrescriba, override, los métodos abstractos e implemente el código faltante que no se definió durante el proceso de abstracción cuando se creó la clase abstracta.
  • Si al menos un método de la clase es declarado abstract, es obligación que la clase completa sea definida como abstract, la clase puede tener el resto de los métodos no abstractos.
  • Los métodos abstract no llevan cuerpo, no llevan las llaves { … }, simplemente termina con un punto y coma “;” 
  • Si una clase hereda a una clase abstracta usando la palabra clave extends  el compilador dará un error de sintaxis, el compilador dejará de dar un error cuando la clase que hereda sobrescriba los métodos abstractos e implemente el código faltante que no se definió durante el proceso de abstracción cuando se creó la clase abstracta.
  • Existe el caso extremo de declarar todos los atributos de una clase con el modificador estático, static, y todos los métodos como abstractos, abstract. En estas clases no hace falta instanciar un objeto de la clase padre o heredada ya que las clases hijas o herederas se harán cargo de implementar todos los métodos abstractos, es suficiente con crear objetos de las clases herederas para acceder a los métodos. El compilador no da error si se crea un objeto de una clase totalmente abstracta, el compilador se queda a la espera que en el futuro se implemente un método no abstracto para la clase padre o que se utilice un constructor de alguno de los hijos al crear una instancia del padre. El compilador se queda esperando que se utilice el poder del polimorfismo.   

¿Cuándo utilizar clases abstractas?

  • Cuando se necesita implementar distintos comportamientos para un mismo método
  • En la fase de análisis, es cuando se intenta definir qué es el problema y se deja la implementación, programación, para más tarde
  • En la fase de diseño, es cuando se intenta definir cómo es el problema y se deja la implementación, programación, para más tarde
  • Cuando se desea usar el mecanismo del polimorfismo, es cuando un objeto cambia de tipo y de comportamiento.
  • Cuando el objetivo es producir código reutilizable por medio del polimorfismo
  • Cuando el objetivo es crear componentes reutilizables
  • Cuando se quiere relacionar dos clases y establecer un medio de comunicación entre las clases 

Forma 1 - Cómo diferir código de una clase abstracta a otra clase usando el operador new



package client1;
public class Main {
    public Main() {
        super();
    }
    private static Figura figura = null;
    public static void main(String[] args) {
        figura = new Figura(1){ //creando un tipo Figura
            @Override
            public float area() {
                return resultado;
            }
        };
       
        System.out.print("Área Figura: " + figura.tipoFigura + "=");
        System.out.println(figura.area()); //línea polimórfica del tipo Figura
       
        figura = new Figura(3, 4){ //creando un tipo Figura
            @Override
            public float area() {
                return resultado;
            }
        };
       
        System.out.print("Área Figura: " + figura.tipoFigura + "=");
        System.out.println(figura.area()); //línea polimórfica del tipo Figura
    }
}

package client1;

public abstract class Figura {
    public Figura() {
        super();
    }
    public Figura(int r) {
        super();
        this.r = r;
        resultado = (float)3.14 * (r * r);
        tipoFigura = "Círculo";
    }
    public Figura(int a, int b) {
        super();
        this.a = a;
        this.b = b;
        resultado = a * b;
        tipoFigura = "Cuadrilátero";
    }
   
    public float a=3, b=4, r=1, resultado=0;
    public String tipoFigura="";
   
    public abstract float area();
}


Para saber más sobre los diagramas Java de Oracle visitar los siguientes sitios



Para saber más sobre los diagramas UML.org visitar los siguientes sitios



¿Qué son las interfaces en Java?

Las interfaces son un tipo de clases Java donde todos sus métodos son abstractos. Una clase declarada como interfaz usando la palabra clave interface es una clase abstracta que tiene todos sus métodos declarados como abstractos. Un método abstracto no tiene código implementado y difiere a que otra clase implemente el código no implementado.
Java es un lenguaje que no permite la herencia múltiple, a acepción de las clases que son declaradas como interfaz. Una clase puede heredar muchas clases que sean declaradas como interfaz. Una clase puede heredar una o más clases del tipo interfaz y la clase que hereda está obligada a implementar el código de la clase heredada.
  •  Las clases abstractas del tipo interfaz no se pueden instanciar.
  • Las clases abstractas del tipo interfaz pueden tener declaraciones de valores constantes, static, final
  • Las clases abstractas del tipo interfaz pueden tener definiciones de métodos abstractos, abstract
  • Para acceder a un valor constante de una interfaz se utiliza su nombre y el operador punto o por medio de la clase que la herede
Las interfaces declaran definiciones de constantes y métodos abstractos, por definición una interfaz es una clase abstracta.
Las interfaces son usadas para definir partes de un producto software, las interfaces son definidas en la fase de análisis del desarrollo de un producto software. Durante la fase de análisis muchos casos de usos se agrupan para definir clases e interfaces. Las clases y las interfaces son consecuencia directa de la agrupación de los datos, casos de usos. Los métodos declarados en las clases y las interfaces serán los encargados de operar con los datos y producir la salida deseada según el problema a resolver.  

Relación entre una clase y una interfaz

La relación entre una interfaz y una clase es una relación que indica que la interfaz es parte de la clase.

En Java hay tres tipos de relaciones:


  1. Relación “Tiene”, es cuando se usa el operador new
  2. Relación “Es del mismo tipo”, es cuando se usa la palabra clave extends
  3. Relación “Es parte”, es cuando se usa la palabra clave implements

En un ambiente de programación Java las palabras agregación y composición se deben entender como actividades y tareas del proceso de abstracción en el desarrollo de un producto software.

Los conceptos de abstracción, agregación y composición no son relaciones en Java, Java tiene tres tipos de relaciones y sus correspondientes palabras claves.

Hay grandes diferencias entre los diagramas UML.org y los diagramas UML Java Oracle, definen distintos estereotipos.

Oracle toma el modelo de referencia UML.org y hereda muchos de los estereotipos definidos por el UML.org y los redefine para crear los diagramas de clases Java específicos para el desarrollo de productos software con el lenguaje Java


El diagrama se lee de la siguiente forma:

La clase VentanaPrincipal y la clase Reloj implementan una parte en común, la parte en común es el método notificarHora(…)
La clase VentanaPrincipal es la responsable de crear una instancia de la clase Reloj y de implementar el código faltante.
La clase Reloj notificará la hora a la clase VentanaPrincipal por medio del código implementado por la clase ventanaPrincipal
  
package client;

import java.awt.Dimension;

import java.awt.Rectangle;

import java.util.Date;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class VentanaPrincipal extends JFrame implements MiNotificador {
    private JLabel jLabel1 = new JLabel();

    public VentanaPrincipal() {
        try {
            jbInit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private Reloj reloj = null;
    private void jbInit() throws Exception {
        this.getContentPane().setLayout( null );
        this.setSize( new Dimension(400, 300) );
        jLabel1.setText("jLabel1");
        jLabel1.setBounds(new Rectangle(55, 50, 270, 30));
        this.getContentPane().add(jLabel1, null);
       
        reloj = new Reloj(){
            @Override
            public void notificarHora(Date date) {
                miNotificarHora(date);
            }
           
        };
        reloj.start();
    }
   
    public void miNotificarHora(Date date) {
        notificarHora(date);
    }

    @Override
    public void notificarHora(Date hora) {
        this.jLabel1.setText(hora.toString());
    }
   
    public static void main(String[] args) {
      VentanaPrincipal vp = new VentanaPrincipal();
      vp.setDefaultCloseOperation(vp.EXIT_ON_CLOSE);
      vp.setLocationRelativeTo(null);
      vp.setVisible(true);
    }
}

package client;
import java.util.Date;
public abstract class Reloj extends Thread implements MiNotificador {
    public Reloj() {
        super();
    }
    public void run() {
        super.run();
        Date date = null;
        do {
            date = new Date();
            notificarHora(date);
            try {
                this.sleep(500);
            } catch (InterruptedException e) {
            }
        } while (true);
    }
    public abstract void notificarHora(Date date);
}

package client;

import java.util.Date;

public interface MiNotificador {
   
    public void notificarHora(Date hora);

}

Heredar clases abstractas


Forma 2 - Cuando se hereda una clase abstracta usando la palabra clave extends

Tres situaciones de heredar clases abstractas


Existen tres situaciones cuando se heredan clases abstractas al momento de crear instancias con new
  1. Se crearán instancias de la clase padre, superclase o abstracta
  2. Se crearán instancias de la clase  padre, superclase o abstracta pero usando los constructores de los hijos, subclases
  3. Se crearán instancias de los hijos, subclases
Nota:
No se puede crear instancias de las clases abstractas, el motivo es que no tienen código implementado. Pero si la clase que intenta crear una instancia de la clase abstracta se hace cargo de implementar el código faltante si se puede crear una instancia de una clase declarada como abstracta.
De la única clase abstracta que no se puede crear instancias es de la clase tipo interfaz. Es obligación que las interfaces sean heredadas para que otra clase se haga cargo del código faltante.  


Situación 1 - Se crearán instancias de la clase padre, superclase o abstracta



La clase Main es la responsable de sobrescribir el método abstracto definido por la clase Figura

package client1;
public class Main {
    public Main() {
        super();
    }
    private static Figura figura = null;
    public static void main(String[] args) {
        figura = new Figura(1){ //creando un tipo Figura
            @Override
            public float area() {
                return resultado;
            }
        };
       
        System.out.print("Área Figura: " + figura.tipoFigura + "=");
        System.out.println(figura.area()); //línea polimórfica del tipo Figura
       
        figura = new Figura(3, 4){ //creando un tipo Figura
            @Override
            public float area() {
                return resultado;
            }
        };
       
        System.out.print("Área Figura: " + figura.tipoFigura + "=");
        System.out.println(figura.area()); //línea polimórfica del tipo Figura
    }
}

package client1;

public abstract class Figura {
    public Figura() {
        super();
    }
    public Figura(int r) {
        super();
        this.r = r;
        resultado = (float)3.14 * (r * r);
        tipoFigura = "Círculo";
    }
    public Figura(int a, int b) {
        super();
        this.a = a;
        this.b = b;
        resultado = a * b;
        tipoFigura = "Cuadrilátero";
    }
   
    public float a=3, b=4, r=1, resultado=0;
    public String tipoFigura="";
   
    public abstract float area();
}

Situación 2 - Se crearán instancias de la clase  padre, superclase o abstracta pero usando los constructores de los hijos, subclases



package client2;

public class Main {

    public Main() {
        super();
    }

    private static Figura figura = null;

    public static void main(String[] args) {

        figura = new Circulo(1); //Creando un tipo Círculo
        System.out.println(figura.area()); //línea polimórfica del tipo Círculo

        figura = new Cuadrilatero(2, 4); //Creando un tipo Cuadrilátero
        System.out.println(figura.area()); //línea polimórfica del tipo Cuadrilátero

    }
}


package client2;

public abstract class Figura {

    public Figura() {
        super();
    }
   
    public float a=3, b=4, r=1, resultado=0;
    public String tipoFigura="";
   
    public abstract float area();
}


package client2;

public class Circulo extends Figura{
    public Circulo(float r) {
        super();
        this.r = r;
        this.tipoFigura = "Círculo";
    }

    @Override
    public float area() {
        resultado = (float)3.14 * (r * r);
        return resultado;
    }
}


package client2;

public class Cuadrilatero extends Figura{
    public Cuadrilatero(int a, int b) {
        super();
        this.a = a;
        this.b = b;
        this.tipoFigura = "Cuadrilátero";
    }

    @Override
    public float area() {
        resultado = a * b;    
        return resultado;
    }   
}


Situación 3 - Se crearán instancias de los hijos, subclases



package client3;

public class Main {

    public Main() {
        super();
    }

    private static Circulo circulo = null;

    private static Cuadrilatero cuadrilatero = null;

    public static void main(String[] args) {

        circulo = new Circulo(1);
        System.out.println("Área círculo = " + circulo.area());

        cuadrilatero = new Cuadrilatero(3,4);
        System.out.println("Área cuadrilátero = " + cuadrilatero.area());

    }
}


package client3;

public abstract class Figura {

    public Figura() {
        super();
    }
   
    public float a=3, b=4, r=1, resultado=0;
    public String tipoFigura="";
   
    public abstract float area();
}


package client3;


public class Cuadrilatero extends Figura {
    public Cuadrilatero(int a, int b) {
        super();
        this.a = a;
        this.b = b;
        tipoFigura = "Cuadrilátero";
    }

    @Override
    public float area() {
        resultado = a * b;    
        return resultado;
    }   
}

package client3;

public class Circulo extends Figura {
    public Circulo(float r) {
        super();
        this.r = r;
        tipoFigura = "Círculo";
    }

    @Override
    public float area() {
        resultado = (float)3.14 * (r * r);
        return resultado;
    }
}

No hay comentarios.:

Publicar un comentario

Realiza un comentario, debes autenticar una cuenta Gmail, Yahoo, OpenID, etc.