viernes, 11 de mayo de 2012

Paquetes


¿Que es un paquete?

      Un paquete es un medio de organización de clases, para agrupar clases e interfaces. Se suelen crear a partir de necesidades funcionales. Pueden contener clases, interfaces y más.
Ejemplo en Java de definición de paquetes:

      package mipaquete.misubpaquete;
     
      public class Persona{
      }

Utilización

      A continuación se presenta un ejemplo en Java de como utilizar un paquete desde una clase ubicada en otro paquete:

      import mipaquete.misubpaquete.*;

La asociación directa es que una clase o una interface esta definida en un archivo. Todo archivo debe contener una clase pulica al menos, y esta debe tener el mismo nombre que el archivo.

Estas clases e interfaces, estos archivos deben vivir dentro de paquetes, que son equivalentes a los directorios, es decir que la clase Persona, que es publica y esta en el archivo Persona.java, debe existir dentro del paquete entidades, es decir el archivo debe vivir dentro del directorio entidades.
Ejemplo:
         /entidades/Persona.java

Interfaz


¿Que es?

      Una interfaz es una declaración de comportamiento, es decir un conjunto de métodos sin su implementación. Define un protocolo de comportamiento. Es un contrato que publica una clase para ser utilizada por otras clases. Puede heredar de otras interfaces.

Ejemplo en Java:

    
public interface Imprimible {
        
         public void imprimir ();
         public void imprimir (Tamaño t, Estilo e);
      }

Utilizacion:

    
public class Documento implements Imprimible{

         public void imprimir(){
         //Acá va la definición.
         }

         public void imprimir(Tamaño t, Estilo e){
         //Acá va la definición.
         }
      }

Ejemplo de mini programa con interfaces:

public class Aeropuerto {
    
    public void darPermisoDeAterrizaje(Volador v){
        
       /*
       Aca va el codigo de despejar pista y permitir aterrizar al volador v
       En el programa se puede iterar sobre una lista de voladores e ir dando
       permiso de aterrizaje a cada volador, sin especificar que tipo 
       especifico de volador se trata 
       */
       
        v.aterrizar();
        
        if(v instanceof AvionPrivado){
            AvionPrivado ap = (AvionPrivado)v;
            System.out.println("Aterrizo Licencia " + ap.getLicencia());
        }
        
         if(v instanceof AvionDePasajeros){
            AvionDePasajeros adp = (AvionDePasajeros)v;
            System.out.println("Aterrizo Licencia " + adp.getAerolinea());
        }
         
       if(v instanceof Superman){
            Superman sp = (Superman)v;
            System.out.println("Aterrizo Licencia " + sp.getNombre());
        }
        
    }
}


Luego tenemos distintos TransportesAereos, un AvionDePasajeros, un AvionPrivado y luego tenemos a Superman.
Entonces lo que se hace es utilizar la interfaz para definir un mismo comportamiento a clases bien distintas, porque no heredan de la misma clase genérica.

public interface Volador {
    //Obligamos a cada volador a programar su modo de aterrizar
    public void aterrizar();
}

public abstract class TransporteAereo {
 }

class AvionPrivado extends TransporteAereo implements Volador{
    
    private String licencia;
    
    @Override
    public void aterrizar() {
      //Aca va el codigo del modo que tiene que aterrizar un avion privado
    }
    
    public String getLicencia() {
        return licencia;
    }
    
     public void setLicencia(String licencia) {
        this.licencia = licencia;
    }
     
}

class AvionDePasajeros extends TransporteAereo implements Volador{

    private String aerolinea;
    
    @Override
    public void aterrizar() {
    //Aca va el codigo del modo que tiene que aterrizar un avion de pasajeros
    }
    
    public String getAerolinea() {
        return aerolinea;
    }
    
     public void setAerolinea(String licencia) {
        this.aerolinea = licencia;
    }
}

class Superman extends TransporteAereo implements Volador{

    @Override
    public void aterrizar() {
    //Aca va el codigo del modo que tiene que aterrizar de Superman
    }
    
    public String getNombre() {
        return "Clark Kent";
    }
    
}



public class Programa {
    public static void main(String[] args) {
        
        AvionPrivado v1 = new AvionPrivado();
        v1.setLicencia("L123456F");
        
        AvionDePasajeros v2 = new AvionDePasajeros();
        v2.setAerolinea("Aerolineas Args");
        
        Superman v3 = new Superman();
        
        Aeropuerto ap = new Aeropuerto();
        
        ap.darPermisoDeAterrizaje(v1);
        
        ap.darPermisoDeAterrizaje(v2);
        
        ap.darPermisoDeAterrizaje(v3);
    }
}


En este caso se ve como se puede llamar al método aterrizar () de los objetos Voladores, porque la interfaz Volador tiene un método aterrizar () y al implementar una interfaz se esta diciendo que se tendrá ese comportamiento, es decir que se implementan sus métodos.

jueves, 10 de mayo de 2012

Clase Abstracta


Definición:

      Una clase abstracta representa un concepto abstracto que no debe ser instanciado. Es simplemente una clase que no se puede instanciar. Sirve como base para que otras clases hereden de ella sus atributos y métodos, pero no tiene sentido por si sola como instancia. Los métodos abstractos no pueden estar definidos en la clase.
      Pero deben ser obligatoriamente definidos en las subclases

Ejemplo en Java:

      public abstract class Persona{   
                 //Atributos
                 private String nombre;
                  private Date fechaDeNacimiento;   
                   //Metodos
                  public abstract void estudiar();
                 public String getNombre(){
                                 return this.nombre;
                   }
      }

Utilizacion:

         public class Hombre extends Persona{   
         //Metodo que se implementa obligatoriamente
        //por estar definido como abstracto en la clase padre
         @Override
            public void estudiar(){
                  //Aca va el codigo de estudiar.
             }   
        }

Polimorfismo


Definición

      El polimorfismo se produce cuando un método adopta más de una forma. Un método puede modificar su comportamiento de acuerdo a su necesidad.

Como ejemplo se puede utilizar lo siguiente:

class Numero {   
    protected int numero;           
    public void proximo(){       
    }   
    @Override
    public String toString(){
        return " " + numero;
    }
}
    class NumeroPositivo extends Numero{       
        public NumeroPositivo(){
          numero = 0;
        }       
        public void proximo(){
        numero = numero + 1;
        }
    }   
    class NumeroNegativo extends Numero{       
        public NumeroNegativo(){
            numero = 0;
        }       
        public void proximo(){
        numero = numero - 1;
        }
    }

public class Programa {         
        public static void main(String[] args) {           
            Numero positivo = new NumeroPositivo();
            Numero negativo = new NumeroNegativo();
            System.out.println("Numero positivo inicial:" + positivo);
            System.out.println("Numero negativo inicial:" + negativo);
            positivo.proximo();
            negativo.proximo();
            System.out.println("Numero positivo siguiente:" + positivo);
            System.out.println("Numero negativo siguiente:" + negativo);
            positivo.proximo();
            negativo.proximo();   
            System.out.println("Numero positivo siguiente:" + positivo);
            System.out.println("Numero negativo siguiente:" + negativo);
            }
}

El resultado de este programa es el siguiente:

Numero positivo inicial: 0
Numero negativo inicial: 0
Numero positivo siguiente: 1
Numero negativo siguiente: -1
Numero positivo siguiente: 2
Numero negativo siguiente: -2

La conclusión que debemos observar en este ejemplo es que se tienen dos instancias de Numero, una instancia de NumeroPositivo y una de NumeroNegativo, cada cual tiene un comportamiento distinto. Sin embargo a la hora de declararlo se los declaro en su forma genérica de Numero y se tiene el método próximo () asociado.

El polimorfismo ha permitido que cada uno se comporte de manera distinta, y sin embargo parece llamarse siempre al mismo método. Es decir, es distinto el próximo negativo del próximo positivo, y eso se refleja en el resultado.

Otra cosa que puede verse en este ejemplo es que al imprimir los objetos positivos y negativos se llama automáticamente al método toString (), es el modo en el que Java imprime sus objetos en pantalla. Y el aprovechamiento del mecanismo de herencia, en la programación del método toString () que retorna el valor de numero como un String, es decir, algo que puede imprimirse fácilmente. Al llamarlo en un NumeroPositivo, como este no lo tiene programado, se ejecuta el que esta definido en la clase padre Numero. Al llamarlo en un NumeroNegativo también se llama al de la clase padre.

Con redefinición:

Se llama polimorfismo con redefinición cuando en una clase sobreescribimos un método, definido en la superclase.

Ejemplo en Java:

      public class Persona{
               public void cantar(){
                                //Esto es un comentario. Aca va la definicion.
                }
      }
      class Cantante extends Persona{
                 public void cantar(){
                               //Esto es un comentario. Aca va la redefinicion.
                 }
      }

En este caso se puede ver que todas las personas pueden cantar (), sin embargo no es lo mismo cantar () en la clase Cantante, pues el cantante logra mayor escala, mayor volumen de voz, y entona de una forma muy preparada. Un cantante logra llegar más lejos con su canto que una persona común. Al redefinir el método en la clase Cantante se logra que se ejecute el método cantar () de cantante en lugar de método cantar () de persona. Por lo tanto la especialización que se logra con este mecanismo permite cambiar el comportamiento de una familia de clases.

Sin Redefinición

Se llama polimorfismo sin redefinición cuando un método tiene distinto comportamiento de acuerdo a la clase a la que pertenece.

Ejemplo en Java:

      public class Persona{
                               public void beber(Agua unPocoDeAgua){
                                 //Esto es un comentario. Aca va la definicion.
                                 }
      }

      class Animal{
                   public void beber(Agua unPocoDeAgua){
                               //Esto es un comentario. Aca va otra definicion.
                               }
      }

En este caso ambas clases logran beber (), es decir que ambas clases tienen definido el método beber, solo que uno de los métodos beber lo hace como humano, y otro lo hace como un animal, el comportamiento es bien distinto, aunque el nombre sea el mismo.

lunes, 7 de mayo de 2012

Casteos


Definición:
      El casteo (casting) es un procedimiento para transformar una variable primitiva de un tipo a otro, o transformar un objeto de una clase a otra clase siempre y cuando haya una relación de herencia  entre ambas.
      Existen distintos tipos de casteo (casting) de acuerdo a si se utilizan tipos de datos o clases.

Casteo Implícito (Widening Casting)
      El casteo implícito radica en que no se necesita escribir código para que se lleve a cabo. Ocurre cuando se realiza una conversión ancha – widening casting – es decir, cuando se coloca un valor pequeño en un contenedor grande.
      Ejemplo:
               
                //Define una variable de tipo int  con el valor 100
                int numeroEntero = 100;
                //Define una variable de tipo long a partir de un int
                long numeroLargo = numero;

Casteo Explicito (Narrowing Casting)
      El casteo explicito se produce cando se realiza una conversión estrecha – narrowing casting – es decir, cuando se coloca un valor grande en un contenedor pequeño. Son susceptibles de perdida de datos y deben realizarse a través de código fuente, de forma explicita.
      Ejemplo:
               
                //Define una variable del tipo int con el valor 250
                int numeroEntero = 250;
                //Define una variable del tipo short y castea la variable numero
                short s = (short) numero;

Upcasting

El upcasting se produce a nivel objetos. Suponiendo que existe una clase Empleado y clase Ejecutivo, la cual es una subclase de esta. Un Ejecutivo entonces ES UN Empleado y se puede escribir de la siguiente forma:
     
      //Instancia un ejecutivo en una variable de tipo Empleado
      Empleado e1 = new Ejecutivo (“Maximo Dueño”, 2000);

A esta operación en donde un objeto de una clase derivada se asigna a una referencia cuyo tipo es alguna de las superclases se la denomina upcasting.
Cuando se realiza este tipo de operaciones, hay que tener cuidado porque para la referencia e1 no existen los atributos y métodos que se definieron en la clase Ejecutivo, aunque la referencia apunte a un objeto de este tipo.
Por el contrario, si ahora existe una variable de tipo Empleado y se desea acceder a los métodos de la clase derivada – suponiendo  que contiene un método ejecutarPlanificacion() en la clase Ejecutivo – teniendo una referencia de una clase base, como en el ejemplo anterior, hay que convertir explícitamente la referencia de un tipo  a otro. Esto se hace con el operador de cast de la siguiente forma:

      //Instancia un ejecutivo en una variable de tipo Empleado
      Empleado emp = new Ejecutivo (“Máximo Dueño”, 2000);

      //Se convierte (o castea) la referencia de tipo
      Ejecutivo ej = (Ejecutivo) emp;

      //Usamos el método de la clase Ejecutivo
      ej.ejecutarPlanificacion();

La expresión de la segunda línea convierte la referencia de tipo Empleado asignándola a una referencia de tipo Ejecutivo. Para el compilador es correcto porque Ejecutivo es una clase derivada de Empleado. En tiempo de ejecución la JVM convertirá la referencia si efectivamente emp apunta a un objeto de la clase Ejecutivo, caso contrario lanzara una excepción.
Por el contrario, si intenta realizar lo siguiente:

      Empleado emp = new Empleado (“Mario Gómez”, 2000);
      Ejecutivo ej = (Ejecutivo) emp;

No dará problemas de compilación, pero al ejecutar se pero al ejecutar se producirá un error ya que la referencia emp apunta a un objeto de la clase Empleado y no a un objeto de clase Ejecutivo.