% Activate the following line by filling in the right side. If for example the name of the root file is Main.tex, write
% "...root = Main.tex" if the chapter file is in the same directory, and "...root = ../Main.tex" if the chapter is in a subdirectory.
 
%!TEX root =  ../notas_java.tex

\chapter[Diseño de Clases en Java]{Diseño de Clases en Java}

\section{Repaso de Clases y Objetos}

En general una clase en Java representará un objeto. Las clases en Java tendrán atributos y métodos, los atributos estas relacionados con las características del objeto como pueden ser tamaño, color, forma, etc y los métodos están asociados a operaciones o funciones con o sobre los atributos.

\begin{verbatim}
class carro{

//atributos

	private int color;
	...

// **************************
	métodos

	public acelerar() {
	 ....
	}
}
\end{verbatim}

\section{Anatomía de una Clase (java y UML)}

Clase 

\begin{enumerate}
	\item Atributos
	\begin{enumerate}
		\item Estáticos : las variables y los métodos marcados con el modificador 'static', son variables y/o métodos que pertenecen a la clase, no a una instancia de dicha clase en particular
		\item Dinámicos : básicamente los métodos no estáticos o dinámicos, se usan para trabajar sobre una instancia de un objeto. 
		\item Visibilidad
		\begin{enumerate}
			\item Private : Sólo se puede acceder al elemento desde métodos de la clase, o sólo puede invocarse el método desde otro método de la clase. 
			\item Protectec : es visible para esa clase y sus clases heredadas el uso puede ser el mismo que private
			\item Public :Todo el mundo puede acceder al elemento. Si es un dato miembro, todo el mundo puede ver el elemento, es decir, usarlo y asignarlo. Si es un método todo el mundo puede invocarlo. 
			\item Fiendly : significa que todas las clases del paquete actual tienen acceso al miembro amistoso , pero todas las clases fuera del paquete tienen un acceso privado a este método
		\end{enumerate}
	\end{enumerate}
	\item Métodos
	\begin{enumerate}
		\item Constructores : Su función es iniciar los atributos de un objeto.
		\item Consultores : Permiten ver los contenidos de los atributos. Estos se hacen con el propósito de garantizar el encapsulamiento de los datos.
		\item Modificadores : Modifican el contenido de los atributos.
		\item Habituales : Cualquier método para realizar una tarea especifica 
		\item Visibilidad : Se utilizan los mismos modificadores de visibilidad que los atributos
	\end{enumerate}
\end{enumerate}

\section{Encapsulación}

Java, como un lenguaje orientado a objetos, que implementa la encapsulación. Este concepto consiste en la ocultación del estado o de los datos miembro de un objeto o atributos, de forma que sólo es posible modificar los mismos mediante los métodos definidos para dicho objeto. Con esto se tiene control sobre los atributos que pueda llegar a tener un objeto, así por ejemplo un circulo no puede tener radio negativo.

\begin{verbatim}
public class circulo {

    private double radio;
    
    public void asigna_radio(double unRadio) {
        radio = unRadio > 0 ? unRadio : 0;
    }
    
    public double obten_radio(){
        return radio;
    }
}
\end{verbatim}

Cada objeto está aislado del exterior, de forma que la aplicación es un conjunto de objetos que colaboran entre sí mediante el paso de mensajes invocando sus operaciones o métodos. De esta forma, los detalles de implementación permanecen ocultos a las personas que usan las clases, evitando así modificaciones o accesos indebidos a los datos que almacenan las clases.

Además, el usuario de la clase no se tiene que preocupar de cómo están implementados los métodos y propiedades, concentrándose sólo en cómo debe usarlos.

La encapsulación es una de las principales ventajas que proporciona la programación orientada a objetos. Como ejemplo tenemos el siguiente código

\begin{verbatim}
public class MiClase {
    private int tipo;
    
    public void setTipo(int untipo) {
        tipo = untipo;
    }
    
    public int getTipo() {
        return tipo;
    }
    
    public static void main(String args[]){
        MiClase mc = new MiClase();
        mc.setTipo(5);
        
        System.out.println("Dato = " + mc.gerTipo());
    }         
}
\end{verbatim}

\section{Anatomía de un método}

En général un método de Java puede ser representado por:

un\_modificador\_acceso visibilidad\_accesar\_metodo valor\_retorna Nombre\_metodo(Variables\_que\_recibe) \{

\}

\begin{enumerate}
\item Modificadores de acceso
	\begin{enumerate}
		\item Estáticos : los métodos marcados con el modificador 'static', métodos 
		que pertenecen a la clase, no a una instancia de dicha clase en particular
		\item Dinámicos : básicamente los métodos no estáticos o dinámicos, se usan para trabajar sobre una 
		instancia de un objeto.
	\end{enumerate}
\item Visibilidad de acceso
\item Valores de retorno: cualquier tipo de datos u objeto que se desea regresar
\item Nombre del método : Los nombres de los método normalmente especifican lo que este hace
\item Variables del método: Conjunto de tipos de variable u objetos que el método necesita
\end{enumerate}

Como ejemplo podemos ver:

\begin{verbatim}
static public void main(String args[]) {
}
\end{verbatim}

Otro ejemplo
\begin{verbatim}
public class AnatomiaMetodo {
    public static void miMetodo1() {
        System.out.println("Metodo estatico");
    }
    
    public void miMetodo2() {
        System.out.println("Metodo dinamico");
    }

}
\end{verbatim}

Para probar hacer

\begin{verbatim}
public class prueba_AnatomiaMetodo {
    static public void main(String args[]) {
        AnatomiaMetodo.miMetodo1();
        AnatomiaMetodo a = new AnatomiaMetodo();
        
        a.miMetodo2();
        AnatomiaMetodo.miMetodo2();
    }

}
\end{verbatim}

\section{Revisión de constructores}

Un constructor es un método especial de una clase que se llama automáticamente siempre que se declara un objeto de esa clase. Su función es inicializar el objeto y sirve para asegurarnos que los objetos siempre contengan valores válidos.

Cuando se crea un objeto en Java se realizan las siguientes operaciones de forma automática:

1.  Se asigna memoria para el objeto.

2. Se inicializan los atributos de ese objeto con los valores predeterminados por el sistema.

3. Se llama al constructor de la clase que puede ser uno entre varios.

El constructor de una clase tiene las siguientes características:

Tiene el mismo nombre que la clase a la que pertenece.

En una clase puede haber varios constructores con el mismo nombre y distinto número de argumentos (se puede sobrecargar)

No se hereda.

No puede devolver ningún valor (incluyendo void).

Debe declararse público (salvo casos excepcionales) para que pueda ser invocado desde cualquier parte donde se desee crear un objeto de su clase.

MÉTODO CONSTRUCTOR POR DEFECTO

Si para una clase no se define ningún método constructor se crea uno automáticamente por defecto. El constructor por defecto es un constructor sin parámetros que no hace nada. Los atributos del objeto son iniciados con los valores predeterminados por el sistema. Por ejemplo, en la clase Fecha:

\begin{verbatim}
import java.util.*;
public class Fecha {

    private int dia;
    private int mes;
    private int año;
  
    private boolean esBisiesto() {
        return ((año % 4 == 0) && (año % 100 != 0) || (año % 400 == 0));
    }

    public void setDia(int d) {
       dia = d;
    }

    public void setMes(int m) {
        mes = m;
    }

    public void setAño(int a) {
        año = a;
    }

    public void asignarFecha() {
        Calendar fechaSistema = Calendar.getInstance();
        setDia(fechaSistema.get(Calendar.DAY_OF_MONTH));
        setMes(fechaSistema.get(Calendar.MONTH));
        setAño(fechaSistema.get(Calendar.YEAR));
    }

    public void asignarFecha(int d) {
        Calendar fechaSistema = Calendar.getInstance();
        setDia(d);
        setMes(fechaSistema.get(Calendar.MONTH));
        setAño(fechaSistema.get(Calendar.YEAR));
    }

    public void asignarFecha(int d, int m) {
        Calendar fechaSistema = Calendar.getInstance();
        setDia(d);
        setMes(m);
        setAño(fechaSistema.get(Calendar.YEAR));
    }

    public void asignarFecha(int d, int m, int a) {
        setDia(d);
        setMes(m);
        setAño(a);
    }

    public int getDia() {
        return dia;
    }

    public int getMes() {
        return mes;
    }

    public int getAño() {
        return año;
    }

    public boolean fechaCorrecta() {
        boolean diaCorrecto, mesCorrecto, anyoCorrecto;
        anyoCorrecto = (año > 0);
        mesCorrecto = (mes >= 1) && (mes <= 12);
        switch (mes) {
            case 2:
                if (esBisiesto()) {
                    diaCorrecto = (dia >= 1 && dia <= 29);
                } else {
                    diaCorrecto = (dia >= 1 && dia <= 28);
                }
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                diaCorrecto = (dia >= 1 && dia <= 30);
                break;
            default:
                diaCorrecto = (dia >= 1 && dia <= 31);
        }
        return diaCorrecto && mesCorrecto && anyoCorrecto;
    }
}
\end{verbatim}

no se ha definido ningún constructor, por lo que al declarar un objeto el compilador utilizará un constructor por defecto. En este caso el método constructor por defecto es:

\begin{verbatim}
Fecha() { }
\end{verbatim}

Vamos a añadir un constructor a la clase Fecha para poder iniciar los atributos de los nuevos objetos con valores determinados que se envían como parámetros. Si los valores corresponden a una fecha incorrecta se asigna la fecha del sistema:

\begin{verbatim}
public Fecha(int d, int m, int a) {
        dia = d;
        mes = m;  
        año = a;

        if (!fechaCorrecta()) {
            Calendar fechaSistema = Calendar.getInstance();
            setDia(fechaSistema.get(Calendar.DAY_OF_MONTH));
            setMes(fechaSistema.get(Calendar.MONTH));
            setAño(fechaSistema.get(Calendar.YEAR));
        }
}
\end{verbatim}

Con este método constructor podremos crear objetos de la siguiente manera:

\begin{verbatim}
Fecha fecha1 = new Fecha(10,2,2011);
\end{verbatim}

Se crea un objeto fecha1 y se le asignan esos valores a sus atributos.

Si se crea un objeto con una fecha no válida:

\begin{verbatim}
Fecha fecha2 = new Fecha(10,20,2011);
\end{verbatim}

A dia, mes y año se les asignará los valores del sistema. Java crea un constructor por defecto si no hemos definido ninguno en la clase, pero si en una clase definimos un constructor ya no se crea automáticamente el constructor por defecto, por lo tanto si queremos usarlo deberemos escribirlo expresamente dentro de la clase.

En este ejemplo hemos definido un método constructor por lo que también es necesario poner el método constructor por defecto.

public Fecha(){}

Este constructor se invocará cuando se declare un objeto sin parámetros.
La clase tiene ahora dos constructores por lo que podemos crear objetos Fecha de dos formas:

\begin{verbatim}
Fecha f1 = new Fecha();   //se ejecuta el constructor sin parámetros
Fecha f2 = new Fecha(1,1,2010); //se ejecuta el constructor con parámetros
\end{verbatim}

INVOCAR A UN MÉTODO CONSTRUCTOR

Un constructor se invoca cuando se crea un objeto de la clase mediante el operador new.
Si es necesario invocarlo en otras situaciones, la llamada a un constructor solo puede realizarse desde dentro de otro constructor de su misma clase y debe ser siempre la primera instrucción.
Si tenemos varios métodos constructores en la clase, podemos llamar a un constructor desde otro utilizando this.
Por ejemplo, si en el constructor con parámetros de la clase Fecha fuese necesario llamar al constructor sin parámetros de la misma clase escribimos:

\begin{verbatim}
public Fecha(int d, int m, int a) {
         this();  //llamada al constructor sin parámetros
         dia = d;
         ……….
}
\end{verbatim}

CONSTRUCTOR COPIA
Se puede crear un objeto a partir de otro de su misma clase escribiendo un constructor llamado constructor copia.
Este constructor copia los atributos de un objeto existente al objeto que se está creando.
Los constructores copia tiene un solo argumento, el cual es una referencia a un objeto de la misma clase que será desde el que queremos copiar.
Por ejemplo, para la clase Fecha podemos escribir un constructor copia que permita crear objetos con los valores de otro ya existente:

\begin{verbatim}
Fecha fecha = new Fecha(1,1,2011);   //se invoca al constructor con parámetros
Fecha fecha1 = new Fecha(fecha);  //se invoca al constructor copia
\end{verbatim}

El constructor copia que escribimos para la clase es:
//constructor copia de la clase Fecha

\begin{verbatim}
public Fecha(final Fecha f) {
        dia = f.dia;
        mes = f.mes;  
        año = f.año;
}
\end{verbatim}

El constructor copia recibe una referencia al objeto a copiar y asigna sus atributos uno a uno a cada atributo del objeto creado.
Declarar el parámetro como final no es necesario pero protege al objeto a copiar de cualquier modificación accidental que se pudiera realizar sobre él. 


\section{Miembros estáticos}

Las variables de clase o miembros estáticos son aquellos a los que se antepone el modificador static. Vamos a comprobar que un miembro dato estático guarda el mismo valor en todos los objetos de dicha clase.

Sea una clase denominada Alumno con dos miembros dato, la nota de selectividad, y un miembro estático denominado nota de corte. La nota es un atributo que tiene un valor distinto para cada uno de los alumnos u objetos de la clase Alumno, mientras que la nota de corte es un atributo que tiene el mismo valor para a un conjunto de alumnos. Se define también en dicha clase una función miembro que determine si está (true) o no (false) admitido.

\begin{verbatim}
public class Alumno {
    double nota;
    static double notaCorte=6.0;
    public Alumno(double nota) {
        this.nota=nota;
    }
    boolean estaAdmitido(){
        return (nota>=notaCorte);
    }
} 
\end{verbatim}

Creamos ahora un array de cuatro alumnos y asignamos a cada uno de ellos una nota.

\begin{verbatim}
        Alumno[] alumnos={new Alumno(5.5), new Alumno(6.3), 
		new Alumno(7.2), new Alumno(5.0)};
\end{verbatim}

Contamos el número de alumnos que están admitidos

\begin{verbatim}
        int numAdmitidos=0;
        for(int i=0; i<alumnos.length; i++){
            if (alumnos[i].estaAdmitido()){
                numAdmitidos++;
            }
        }
        System.out.println("admitidos "+numAdmitidos);
\end{verbatim}

Accedemos al miembro dato notaCorte desde un objeto de la clase Alumno, para cambiarla a 7.0

\begin{verbatim}
        alumnos[1].notaCorte=7.0;
\end{verbatim}

Comprobamos que todos los objetos de la clase Alumno tienen dicho miembro dato estático notaCorte cambiado a 7.0

\begin{verbatim}
        for(int i=0; i<alumnos.length; i++){
            System.out.println("nota de corte "+alumnos[i].notaCorte);
        }
\end{verbatim}

El miembro dato notaCorte tiene el modificador static y por tanto está ligado a la clase más que a cada uno de los objetos de dicha clase. Se puede acceder a dicho miembro con la siguiente sintaxis

\begin{verbatim}
	Nombre_de_la_clase.miembro_estático
\end{verbatim}

Si ponemos

\begin{verbatim}
        Alumno.notaCorte=6.5;
        for(int i=0; i<alumnos.length; i++){
            System.out.println("nota de corte "+alumnos[i].notaCorte);
        }
\end{verbatim}

Veremos que todos los objetos de la clase Alumno habrán cambiado el valor del miembro dato estático notaCorte a 6.5.

Un miembro dato estático de una clase se puede acceder desde un objeto de la clase, o mejor, desde la clase misma.

\section{Relaciones entre clases}

\section{Interfaces}

Una interfaz en java es un conjunto de métodos abstractos y propiedades. En ellas se especifica qué se debe hacer pero no su implementación. Serán las clases que implementen estas interfaces las que describan la lógica del comportamiento de los métodos.

Ventajas al utilizar interfaces:
\begin{enumerate}
\item Se organiza la programación.
\item Obligar a que ciertas clases utilicen los mismos métodos (nombres y parámetros).
\item Establecer relaciones entre clases que no estén relacionadas.
\end{enumerate}

¿Cómo usarlas?

Java utiliza dos palabras reservadas para trabajar con interfaces que son interface e  implements. Para declarar una interfaz se debe seguir el siguiente orden:

\begin{verbatim}
modificador_acceso interface NombreInterfaz 
{
    código de interfaz
}
\end{verbatim}

El modificador de acceso permitido dentro de una interfaz es public o puede no existir. Los atributos que definamos en el cuerpo de la interfaz serán atributos de tipo constante en las clases en las que se implemente.

Para implementar una interfaz en una clase se debe seguir el siguiente orden:

\begin{verbatim}
modificador_acceso NombreClase implements NombreInterfaz1 [, NombreInterfaz2]
\end{verbatim}

NOTA: Una clase puede implementar varias interfaces, separando los nombres por comas.

Ejemplo:

\begin{verbatim}
Definición de una interfaz:
    interface Nave 
    {
        public static final int VIDA = 100;
 
        public abstract void moverPosicion (int x, int y);
        public abstract void disparar();
        .....
    }
\end{verbatim}

Uso de la interfaz definida:

\begin{verbatim}
    public class NaveJugador implements Nave 
    {
        public void moverPosicion (int x, int y)
        {
            //Implementación del método
        }
        public void disparar()
        {
            //Implementación del método
        }
        .....
    }
\end{verbatim}

En resumen los métodos forman la interfaz del objeto con el mundo exterior, un ejemplo, los botones en el frente del televisor, son la interfaz entre el usuario y el cableado eléctrico en el otro lado de la carcasa de plástico. Presiona el botón "POWER" para encender o apagar el televisor.


En su forma más común, una interfaz es un grupo de métodos relacionados con cuerpos vacíos. El comportamiento de una bicicleta, si se especifica como una interfaz, podría aparecer como sigue:

\begin{verbatim}
interface Bicicleta

{
       void changeCadence(int newValue); // Revoluciones de la rueda por minuto
       void changeGear(int newValue);
       void speedUp(int increment);
       void applyBrakes(int decrement);
}
\end{verbatim}

Para implementar esta interfaz, el nombre de la clase debe cambiar (a una marca concreta de la bicicleta, por ejemplo, como ACMEBicycle), y tendrá que utilizar la palabra clave implements en la declaración de la clase:

\begin{verbatim}
    ACMEBicycle clase implements Bicicleta 
    (// resto de esta clase implementada como antes)
\end{verbatim}

Al implementar una interfaz esto permite que la clase se vuelva más formal sobre el comportamiento que se compromete a proporcionar.

\section{Herencia}

La herencia es un mecanismo que permite la definición de una clase a partir de la definición de otra ya existente. La herencia permite compartir automáticamente métodos y datos entre clases, subclases y objetos.

La herencia está fuertemente ligada a la reutilización del código en la OOP. Esto es, el código de cualquiera de las clases puede ser utilizado sin más que crear una clase derivada de ella, o bien una subclase.

Hay dos tipos de herencia: Herencia Simple y Herencia Múltiple. La primera indica que se pueden definir nuevas clases solamente a partir de una clase inicial mientras que la segunda indica que se pueden definir nuevas clases a partir de dos o más clases iniciales. Java sólo permite herencia simple.

\subsection{Subclases}

El concepto de herencia conduce a una estructura jerárquica de clases o estructura de árbol, lo cual significa que en la OOP todas las relaciones entre clases deben ajustarse a dicha estructura.

En esta estructura jerárquica, cada clase tiene sólo una clase padre. La clase padre de cualquier clase es conocida como su superclase. La clase hija de una superclase es llamada una subclase.

* Una superclase puede tener cualquier número de subclases.

* Una subclase puede tener sólo una superclase. 

\subsection{Sobreescritura de métodos}

Cada vez que se tiene una clase que hereda un método de una superclase, se tiene la oportunidad de sobreescribir el método (a menos que dicho método esté marcado como final). El beneficio clave al sobreescribir un método heredado es la habilidad de definir un comportamiento específico para los objetos de la subclase.Veamos un ejemplo de la sobreescritura de un método heredado:

\begin{verbatim}
public class Animal {

   public void comer(){
      System.out.println("Animal comiendo...");
   }
}

class Caballo extends Animal{
   public void comer(){
      System.out.println("Caballo comiendo...");
   }
}
\end{verbatim}

Al momento de que Caballo hereda de la clase Animal obtiene el método comer() definido en Animal, sin embargo, se desea especificar un poco más el comportamiento de Caballo al momento de llamar a comer(), por lo tanto se define un método con el mismo nombre dentro de la clase Caballo. Debido a que ambos métodos tienen el mismo nombre, para saber qué método se invocará en tiempo de ejecución es necesario saber a qué objeto se está refiriendo. P. ej.:

\begin{verbatim}
public static void main(String... args){
   Animal a = new Animal();
   Caballo c = new Caballo();
   a.comer();
   c.comer();
}
\end{verbatim}


Al ejecutar el código anterior obtenemos lo siguiente:

\begin{verbatim}
Animal comiendo...
Caballo comiendo...
\end{verbatim}

Ahora en su versión polimórfica:

\begin{verbatim}
public static void main(String... args){
   Animal a = new Caballo();
   Caballo c = new Caballo();
   a.comer();
   c.comer();
}
\end{verbatim}

Obtenemos lo siguiente:

\begin{verbatim}
Caballo comiendo...
Caballo comiendo...
\end{verbatim}

En la primera ejecución del método tenemos una referencia a un Animal pero el objeto es un Caballo, por lo tanto, el método invocado es la versión definida en la clase Caballo. Es importante mencionar que al momento de invocar un método sobre una referencia Animal en un objeto Caballo solamente se podrá ejecutar el métodos si la clase Animal lo define, p. ej.:

\begin{verbatim}
class Animal {

   public void comer(){
      System.out.println("Animal comiendo...");
   }
}

class Caballo extends Animal{
   public void comer(){
      System.out.println("Caballo comiendo...");
   }
   public void relinchar(){
      System.out.println("Caballo relinchando...");
   }
}

class ProbarMetodos{

   public static void main(String... args){
      Animal a = new Caballo();
      Caballo c = new Caballo();
      a.comer();
      c.comer();
      a.relinchar(); //error!
   }
}
\end{verbatim}

Aún cuando la clase Caballo define un método llamado relinchar(), la clase Animal no sabe que dicho método existe, por lo tanto, el compilador arrojará un error cuando se intente invocar al método relinchar()  desde una referencia Animal, no importa que el objeto Caballo sí lo tenga.

Reglas para sobreescribir un método::

Las reglas básicas para la sobreescritura de métodos son las siguientes:

+ La lista de argumentos del método debe ser exactamente la misma.

+ El tipo de retorno debe de ser el mismo o un subtipo del tipo de retorno declarado originalmente.

+ El nivel de acceso no debe de ser más restrictivo.

+ El nivel de acceso puede ser menos restrictivo.

+ Los métodos de instancia pueden ser sobreescritos solamente si han sido heredados por la subclase.

+ Los métodos sobreescritos pueden arrojar cualquier excepción no verificada(de tiempo de ejecución) por el compilador.

+ Los métodos sobreescritos NO pueden arrojar excepciones verificadas por el compilador.

+ No se puede sobreescibir un método marcado como final.

+ No se puede sobreescibir un método marcado como estático (static).

+ Si un método no puede ser heredado, no puede ser sobreescrito.

Invocar la versión de la superclase de un método sobreescrito::

En algunas ocasiones necesitamos invocar al método escrito en la superclase en lugar de la versión que hemos sobreescrito, para ello se utiliza la palabra super seguida de un punto(.) y posteriormente el nombre del método a invocar, p. ej.:

\begin{verbatim}
class Caballo extends Animal{
      public void comer(){
      super.comer();
   }
}
\end{verbatim}

\subsection{Visibilidad}

\subsection{ejemplo}

Como ejemplo básico de herencia implementamos la clase Ciudadano hereda desde la clase Persona, para tomar funcionalidad y extenderla

\begin{verbatim}
class Humano {
    protected String nombre;
    protected String apellido;
    public Humano(String nombre,String apellido) {
        this.nombre = nombre;
        this.apellido = apellido;
    }
    public String nombreCompleto() {
        return this.apellido + ", " + this.nombre;
    }
    public String identificacion() {
        return this.nombreCompleto();
    }  
}

class Ciudadano extends Humano {
    protected String documento;

    public Ciudadano(String nombre,String apellido, String documento) {
        super(nombre,apellido);
        this.documento = documento;
    }

    public String identificacion() {
        return super.identificacion() + ", documento: " + this.documento;
    }
}


public class Herencia {
    public static void  main (String args[]) {
        Humano a = new Humano("Emilio","Rosso");
        Ciudadano b = new Ciudadano("Emilio","Rosso","3052454545");
        Humano [] arregloDeHumanos;
        arregloDeHumanos.push(a);
        arregloDeHumanos.push(b);
        identificarPolimorfico(arregloDeHumanos);
    }

    public static void identificarPolimorfico(
      Humano [] arregloDeHumanos) {
        for(int i = 0; i < arregloDeHumanos.length ; i++) {
            System.out.println("Identificando: " + 
            arregloDeHumanos[i].identificacion());
        }
    }

}
\end{verbatim}

\section{Polimorfismo}

El polimorfismo consiste en obtener un mismo método con diferentes funciones, es decir, suponiendo que tengamos una clase Saludo con el método Saludo el cual sería su constructor, pero en este caso tendríamos varios constructores pero siempre siguiendo las reglas de independencia en cuestión a los parámetros de cada constructor para que así puedan diferenciarse uno de otro, sin embargo cada uno tendrá diferentes procesos internos en sí mismo.

\begin{verbatim}
class Saludo {
	public Saludo(){
      		MensajeSaludo="Hola Amigo";
	}
	public Saludo(String Palabra){
      		MensajeSaludo=Palabra;
	}
	public Saludo(String Palabra, String Nombre){
		MensajeSaludo=Palabra.concat(" ").concat(Nombre);
	} 
}
\end{verbatim}

\subsection{Polimorfismo usando herencia}

Mediante el polimorfismo podemos variar las propiedades de un objeto que a heredado de otra clase, veamos esto siguiendo un ejemplo :

\begin{verbatim}
	public class concede {
		public void estoyEscribiendo(){
			System.out.println("Escribo una nota");
		}
	}
	public class acepta extends concede {
	
	}
	
    public class Herencia {
        public static void main(String[] args) {
            acepta herencia = new acepta();
            concede herenciaDos = new concede();
            herencia.estoyEscribiendo();
            herenciaDos.estoyEscribiendo();
        }
    }
\end{verbatim}

Al ejecutar el anterior código nos desplegara dos veces el mensaje:

\begin{verbatim}
    Escribo una nota
    Escribo una nota
\end{verbatim}

Mediante el polimorfismo podemos hacer que la clase acepta que es la que extiende a todas las propiedades de concede pueda modificar aquello datos que recibe, en nuestro ejemplo haremos lo siguiente:

    package conceptos;

    public class acepta extends concede {
        public void estoyEscribiendo(){
            System.out.println("Tu también escribes una nota");
        }
    }

Este es un ejemplo claro de polimorfismo ya que la clase acepta esta heredando todo lo que tiene la clase concede, lo que realizamos en esta clase es añadir un polimorfismo y sobre escribir lo que heredamos, es decir tenemos estoyEscribiendo que hemos heredado pero estamos sobrescribiendo lo que he heredado, en pocas palabras estoy sobrescribiendo el método que he heredado cambiando el mensaje que voy a desplegar.

\subsection{Polimorfismo usando Interfaces}

\section{Revisión de Excepciones}

En esta sección haremos una revisión de las excepciones haciendo uso de todas las herramientas vistas en el capítulo

\subsection{Ejemplo 1}

Como ejemplo de aplicación de la herencia y de manejo de interfaces haremos un ventana de tipo windows que maneje algunas acciones que se desencadenaran cuando se presione un botón o se de enter en un cuadro de texto. Ente ejemplo lo llevaremos a cabo en 4 pasos que se detallan a continuación.

\textbf{Paso 1}

Definir Ventana y crear una Ventana tipo Windows.

\begin{verbatim}
import javax.swing.*;

public class MiVentana extends JFrame{
    public MiVentana() {
        super("Mi Ventana");
        this.setSize(400, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}
\end{verbatim}

\textbf{Paso 2}

Agregar botón, campo de texto y una etiqueta.

\begin{verbatim}
import javax.swing.*;
import java.awt.*;
        

public class MiVentana extends JFrame{
    private JButton miBoton;
    private JTextField miCampoTexto;
    private JLabel miEtiqueta;
           
    public MiVentana() {
        super("Mi Ventana");
        
        this.definirVentana();
        
        this.setSize(400, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    
    public void definirVentana() {
        this.setLayout(new FlowLayout());
        miBoton = new JButton("Enviar");
        miCampoTexto = new JTextField(20);
        miEtiqueta = new JLabel();
        
        this.add(miCampoTexto);
        this.add(miBoton);
        this.add(miEtiqueta);
    }
}
\end{verbatim}

\textbf{Paso 3}

Abstracción y eventos en Java

\begin{verbatim}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
        

public class MiVentana extends JFrame implements ActionListener {
    private JButton miBoton;
    private JTextField miCampoTexto;
    private JLabel miEtiqueta;
           
    public MiVentana() {
        super("Mi Ventana");
        
        this.definirVentana();
        
        this.setResizable(false);
        this.setLocationRelativeTo(null);
        this.setSize(400, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    
    public void definirVentana() {
        this.setLayout(new FlowLayout());
        miBoton = new JButton("Enviar");
        miCampoTexto = new JTextField(20);
        miEtiqueta = new JLabel();
        
        this.add(miCampoTexto);
        this.add(miBoton);
        this.add(miEtiqueta);
        miBoton.addActionListener(this);
    }

    public void actionPerformed(ActionEvent arg0) {
        if(arg0.getSource()== miBoton) {
           miEtiqueta.setText(miCampoTexto.getText());
           miCampoTexto.setText("");
        }
    }
}
\end{verbatim}

\textbf{Paso 4}

Finalmente haremos uso de las excepciones apara que nuestro programa este protegido

\begin{verbatim}
    public void actionPerformed(ActionEvent arg0) {
        if(arg0.getSource() == miBoton) {
            String a = miCampoTexto.getText();
            double val = 0; 
            try {
                val = Double.parseDouble(a);
            }
            catch (NumberFormatException ex) {
                miEtiqueta.setText("Error");
                miCampoTexto.setText("");
                return;
            }
            
            double val2 = val*1.1;
            miEtiqueta.setText("El 10% de " + val + " es " + val2);         
        }     
    }
\end{verbatim}

\textbf{Paso 5}

Otra manera de hacer lo mismo es:

\begin{verbatim}
iimport javax.swing.*;
import java.awt.*;
import java.awt.event.*;
        
public class MiVentana2 extends JFrame {
    private JButton miBoton;
    private JTextField miCampoTexto;
    private JLabel miEtiqueta;
           
    public MiVentana2() {
        super("Mi Ventana 2");
        
        this.definirVentana();
        
        this.setResizable(false);
        this.setLocationRelativeTo(null);
        this.setSize(400, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    
    public void definirVentana() {
        this.setLayout(new FlowLayout());
        miBoton = new JButton("Enviar");
        miCampoTexto = new JTextField(20);
        miEtiqueta = new JLabel();
        
        this.add(miCampoTexto);
        this.add(miBoton);
        this.add(miEtiqueta);
        miBoton.addActionListener((ActionListener) new MiBotonListener());
        miCampoTexto.addKeyListener((KeyListener) new MiCampoTextoKeyListener());
    }

    
    private class MiBotonListener implements ActionListener {    
        public void actionPerformed(ActionEvent arg0) {
            String a = miCampoTexto.getText();
            double val = 0; 
            try {
                val = Double.parseDouble(a);
            }
            catch (NumberFormatException ex) {
                miEtiqueta.setText("Error");
                miCampoTexto.setText("");
                return;
            }
            
            double val2 = val*1.1;
            miEtiqueta.setText("El 10% de " + val + " es " + val2);    
        }
    } 
    
    private class MiCampoTextoKeyListener implements KeyListener {     
        public void keyTyped(KeyEvent arg0) {
            if(arg0.getKeyChar() == '\n' ) {
                String a = miCampoTexto.getText();
                double val = 0; 
                try {
                    val = Double.parseDouble(a);
                }
                catch (NumberFormatException ex) {
                    miEtiqueta.setText("Error");
                    miCampoTexto.setText("");
                    return;
                }

                double val2 = val*1.1;
                miEtiqueta.setText("El 10% de " + val + " es " + val2);    
            }
        
        }

        public void keyPressed(KeyEvent arg0) {
        }

        public void keyReleased(KeyEvent arg0) {

        }
    }    
}
\end{verbatim}

\subsection{Ejemplo 2}

Conversión de Grados Centrigrados a Grados Farenhait.

\begin{verbatim}
import java.awt.FlowLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;


public class Temperatura extends JFrame{
    private JTextField campo1;
    private JTextField campo2;
    private JLabel etiqueta1;
    private JLabel etiqueta2;
    
    public Temperatura() {
        super("Conversion");
        
        this.definirVentana();
        
        this.setResizable(false);        
        this.setSize(200, 300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    
    public void definirVentana() {
        this.setLayout(new FlowLayout());
        campo1 = new JTextField(15);
        campo2 = new JTextField(15);
        etiqueta1 = new JLabel("Grados C");
        etiqueta2 = new JLabel ("Frados F");
       
        this.add(etiqueta1);
        this.add(campo1);
        this.add(etiqueta2);
        this.add(campo2);

        campo1.addKeyListener((KeyListener) new campo1_KeyListener());
        campo2.addKeyListener((KeyListener) new campo2_KeyListener());
    }
    
    private class campo1_KeyListener implements KeyListener {     

        public void keyTyped(KeyEvent arg0) {
            if(arg0.getKeyChar() == '\n' ) {
                String a = campo1.getText();
                double val = 0; 
                try {
                    val = Double.parseDouble(a);
                }
                catch (NumberFormatException ex) {
                    campo1.setText("error");
                    return;
                }
                val = val*9.0/5.0 + 32;
                campo2.setText("" +val);   
            }
        }
        public void keyPressed(KeyEvent arg0) {
        }

        public void keyReleased(KeyEvent arg0) {

        }
    }
    private class campo2_KeyListener implements KeyListener {

        public void keyTyped(KeyEvent arg0) {
            if(arg0.getKeyChar() == '\n' ) {
                String a = campo2.getText();
                double val = 0; 
                try {
                    val = Double.parseDouble(a);
                }
                catch (NumberFormatException ex) {
                    campo2.setText("error");
                    return;
                }

                val = (val - 32)*5.0/9.0;
                campo1.setText("" +val);   
            }
        }
        public void keyPressed(KeyEvent arg0) {
        }
        public void keyReleased(KeyEvent arg0) {

        }       
    }
    
    static public void main(String args[]){
        Temperatura a = new Temperatura();
    }
}
\end{verbatim}

\subsection{Ejemplo 3}

En este ejemplo se hace uso de la clase JPanel para crear paneles de dibujo así como de control. También se implementas los eventos de ratón para manejo en una pantalla de dibujo.

\textbf{Paso 1}

Creación del panel de dibujo

\begin{verbatim}
package Dibujo;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JPanel;

public class Lienzo extends JPanel implements MouseMotionListener, MouseListener {
    private int x0, y0, x1, y1;
    
    public Lienzo(){      
        this.setBackground(Color.WHITE); // Pone un color de fondo
        this.setPreferredSize(new Dimension(400, 400)); // Tamaño del lienzo
        this.addMouseMotionListener(this);
        this.addMouseListener(this);
    }
      
    @Override
    public void paint(Graphics g){
        super.paint(g);
        
        g.drawLine(x0, y0, x1, y1);
    }

    public void mouseDragged(MouseEvent arg0) {
        x1 = arg0.getX();
        y1 = arg0.getY();
        repaint();
    }

    public void mouseMoved(MouseEvent arg0) {
    }

    public void mouseClicked(MouseEvent arg0) {
    }

    public void mousePressed(MouseEvent arg0) {
        x0 = arg0.getX();
        y0 = arg0.getY();
    }

    public void mouseReleased(MouseEvent arg0) {
    }

    public void mouseEntered(MouseEvent arg0) {
    }

    public void mouseExited(MouseEvent arg0) {
    }        
}
\end{verbatim}

Para probar el Lienzo hacemos

\begin{verbatim}
package Dibujo;

import javax.swing.JFrame;

public class PruebaLienzo extends JFrame {
    public PruebaLienzo() {
        super("Prueba Lienzo");
        Lienzo miLienzo = new Lienzo();
        add(miLienzo);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        setVisible(true);
        pack();
    }
    static public void main(String args[]) {
        new PruebaLienzo();
    }
}
\end{verbatim}

\textbf{Paso 2}

Creación de panel de control con botones

\begin{verbatim}
package Dibujo;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Botones extends JPanel implements ActionListener {
    static private int botonPrecionado;
    private String nombres[];
    
    public Botones(String unTitulo, String unNombre[], int N) {
        super(new GridLayout(N/2, 2));
        int i;
        
        nombres = new String[N];
        for(i=0; i<N; i++)
            nombres[i] = unNombre[i];
        
        setBackground(Color.lightGray);
        setBorder(BorderFactory.createTitledBorder(unTitulo));    
        JButton b;
        
        for(i=0; i<N; i++ ) {
            b = new JButton(unNombre[i]);
            b.addActionListener(this);
            this.add(b);          
        }      
    }

    public void actionPerformed(ActionEvent arg0) {
        int i;
        
        for(i=0; i<nombres.length; i++)
            if(nombres[i].equals(arg0.getActionCommand())) {
                botonPrecionado = i;
                break;
            }
        System.out.println(nombres[botonPrecionado]);
    }

}
\end{verbatim}

\textbf{Paso 3}

Panel de control con botones de radio

\begin{verbatim}
package Dibujo;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

public class SeleccionPanel extends JPanel implements ActionListener{
    static private int seleccion;
    private String nombres[];
    
    public SeleccionPanel(String Nombre, String[] opciones, int N){
        super(new GridLayout(N/2, 2));
        int i;
        
        nombres = new String[N];
        for(i=0; i<N; i++)
            nombres[i] = opciones[i];
        
        setBackground(Color.lightGray);
        setBorder(BorderFactory.createTitledBorder(Nombre));
        ButtonGroup group = new ButtonGroup();
        JRadioButton option;
 
        for(i=0; i<N; i++) {
          option = new JRadioButton(opciones[i]);
          option.addActionListener(this);
          group.add(option);
          add(option);  
      }
    }

    public void actionPerformed(ActionEvent arg0) {
        int i;
        
        for(i=0; i<nombres.length; i++)
            if(nombres[i].equals(arg0.getActionCommand())) {
                seleccion= i;
                break;
            }
        System.out.println(nombres[seleccion]);
        
    }
}
\end{verbatim}

\textbf{Paso 4}

Finalmente creamos un programa para probar todas las clases implementadas. 

\begin{verbatim}
package Dibujo;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class PruebaTodo extends JFrame {
    private Botones misBotones;
    private SeleccionPanel miSeleccion;
    private Lienzo miLienzo;
    
    public PruebaTodo () {
        JPanel AreaControl = new JPanel(new GridLayout(2, 1));
        misBotones = new Botones("Botones", 
           new String[] {"uno", "dos", "tres", "cuatro"}, 4);
        miSeleccion = new SeleccionPanel("Algo", 
           new String[] {"a", "b", "c", "d", "e"}, 5);
        
        AreaControl.add(misBotones);
        AreaControl.add(miSeleccion);
        
        miLienzo = new Lienzo();
        this.add(AreaControl, BorderLayout.WEST);    
        this.add(miLienzo,BorderLayout.EAST);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        pack();
        setVisible(true);
    }
    
    static public void main(String args[]) {
        new PruebaTodo();
    }
}
\end{verbatim}