domingo, 28 de junio de 2015

Interfaces

COMPARABLE y SORT (ArrayList)

La implementación de esta interface permite realizar comparaciones entre elementos de un ArrayList o de vectores.
Su sintaxis es:
public class Clase implements Comparable<Clase>

De forma predeterminada, el método de esta interfaz, realiza comparaciones de acuerdo al primer atributo que encuentra en el objeto. Para personalizar la comparación basta con sobreescribir el método compareTo.

Una de las aplicaciones donde toma importancia esta interfaz es cuando se desea obtener una lista ordenada de acuerdo a un determinado criterio, para lo cual basta con agregar la siguiente línea de código:
Collections.sort(lista_a_ordenar);

Así por ejemplo:

Crearé 3 clases: Estudiante, Curso y Aplicación:

En la clase Estudiante:

public class Estudiante {

    private String numeroUnico;
    private String nombre;
    private Calendar fechaNacimiento;
    private Double ira;

    public Estudiante() {
        this.numeroUnico = null;
        this.nombre = null;
        this.fechaNacimiento = null;
        this.ira = 0.0;
    }

    public Estudiante(String numeroUnico, String nombre, Calendar fechaNacimiento, Double ira) {
        this.numeroUnico = numeroUnico;
        this.nombre = nombre;
        this.fechaNacimiento = fechaNacimiento;
        this.ira = ira;
    }

    public String getNumeroUnico() {
        return numeroUnico;
    }

    public void setNumeroUnico(String numeroUnico) {
        this.numeroUnico = numeroUnico;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public Calendar getFechaNacimiento() {
        return fechaNacimiento;
    }

    public void setFechaNacimiento(Calendar fechaNacimiento) {
        this.fechaNacimiento = fechaNacimiento;
    }

    public Double getIra() {
        return ira;
    }

    public void setIra(Double ira) {
        this.ira = ira;
    }

    public Integer obtenerEdad(Calendar fechaNacimiento) {
        Calendar fechaActual = Calendar.getInstance();
        Integer edad = fechaActual.get(Calendar.YEAR) - fechaNacimiento.get(Calendar.YEAR);
        if (fechaActual.get(Calendar.MONTH) < fechaNacimiento.get(Calendar.MONTH)){
            edad = edad-1;
        }
        return edad;
    }

    public Integer calcularMeses(Calendar fechaNacimiento) {
        Integer meses = 0;
        Calendar fechaActual = Calendar.getInstance();
        if (fechaActual.get(Calendar.MONTH) > fechaNacimiento.get(Calendar.MONTH)) {
            meses = fechaActual.get(Calendar.MONTH) - fechaNacimiento.get(Calendar.MONTH);
        } else {
            meses = fechaActual.get(Calendar.MONTH)- fechaNacimiento.get(Calendar.MONTH) + 12;
        }
        return meses;
    }

    @Override
    public String toString() {
        return String.format("\t%s\t%s\t\t%s años, %s mes(es)\t%.2f", this.numeroUnico, this.nombre, obtenerEdad(this.fechaNacimiento), calcularMeses(this.fechaNacimiento), this.ira);
    }
}

En la clase Curso:
public class Curso {
    
    private ArrayList<Estudiante> listaEstudiantes = new ArrayList<Estudiante>();
    
    public ArrayList<Estudiante> getListaEstudiantes() {
        return listaEstudiantes;
    }
    
    public void setListaEstudiantes(ArrayList<Estudiante> listaEstudiantes) {
        this.listaEstudiantes = listaEstudiantes;
    }
    
    public void agregarEstudiante(Estudiante nuevoEstudiante) {
        listaEstudiantes.add(nuevoEstudiante);
    }
    
    public void imprimirLista() {
        System.out.println("***************************ESTUDIANTES***************************");
        System.out.printf("\tNúmero único\tNombre\t\tEdad\t\t\tIRA\n");
        for (Estudiante e : listaEstudiantes) {
            System.out.println(e);
        }
    }
}

En la clase Aplicación:
public class Aplicacion {

    public static void main(String args[]) throws ParseException {
        Curso cr = new Curso();
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        Calendar f1 = Calendar.getInstance();
        f1.setTime(sdf.parse("25-05-1993"));
        Estudiante e1 = new Estudiante("201210080", "Emily", f1, 29.3);
        cr.agregarEstudiante(e1);
        Calendar f2 = Calendar.getInstance();
        f2.setTime(sdf.parse("15-12-1991"));
        Estudiante e2 = new Estudiante("201210180", "Edison", f2, 39.1);
        cr.agregarEstudiante(e2);
        Calendar f3 = Calendar.getInstance();
        f3.setTime(sdf.parse("15-07-1994"));
        Estudiante e3 = new Estudiante("201010080", "Jenny", f3, 40.0);
        cr.agregarEstudiante(e3);
        cr.imprimirLista();
    }
}



Para comparar edades:

Primero se debe implementar la interfaz Comparable: y sobreescribir el método CompareTo:

public class Estudiante implements Comparable<Estudiante> {

@Override
    public int compareTo(Estudiante e) {
        int mayor = 0;
        if (obtenerEdad(this.fechaNacimiento) < e.obtenerEdad(e.getFechaNacimiento())) {
            mayor = -1;
        } else if (obtenerEdad(this.fechaNacimiento) > e.obtenerEdad(e.getFechaNacimiento())) {
            mayor = 1;
        } else {
            if (calcularMeses(this.fechaNacimiento) > e.calcularMeses(fechaNacimiento)) {
                mayor = -1;
            } else if (calcularMeses(this.fechaNacimiento) < e.calcularMeses(fechaNacimiento)) {
                mayor = 1;
            }
        }
        return mayor;
    }
}

Luego crear el método para ordenar la lista en la clase Curso:
 public void ordenar() {
        Collections.sort(listaEstudiantes);
    }

Finalmente, en la clase Aplicacion llamar a los métodos para ordenar e imprimir la lista:

cr.ordenar();
cr.imprimirLista();

El resultado de la ejecución es:



Si se desea ordenar por IRA, hay que sobreescribir el método CompareTo, así:
  
@Override
    public int compareTo(Estudiante e) {
        int mayor = 0;
        if (this.ira < e.getIra()) {
            mayor = -1;
        } else if (this.ira > e.getIra()) {
            mayor = 1;
        }
        return mayor;

    }

El resultado ahora será:

Finalmente para ordenar por Nombre, la sobreescritura del CompareTo es:

@Override
    public int compareTo(Estudiante e) {
        return this.nombre.compareTo(e.getNombre());
    }

Al ejecutar se obtendrá:



CLONEABLE

En ocasiones es necesario realizar una copia del contenido de cada campo de un objeto y sería erróneo realizarlo mediante asignación pues se tendrían dos objetos apuntando a una misma dirección de memoria lo que se vería repercutido en que si se cambiara posteriormente el valor de uno se verá también afectado en el otro objeto, para solucionar este inconveniente se puede implementar la interfaz cloneable de java y usar el método clone() para realizar el duplicado de un objeto. Por ejemplo:

Ahora sólo usaré dos clases, la clase Estudiante y la clase Aplicación; en la clase Estudiante se implementará la interfaz Cloneable y se sobreescribirá el método clone(), los atrributos, constructores, getters, setters, toString() y los métodos para calcular la edad serán los mismos usados en el ejemplo anterior, el método clone() tendrá el siguiente código:

public class Estudiante implements Cloneable{
    ...
    ...
    ...

    @Override
    public Estudiante clone(){
        Estudiante estClonado = new Estudiante(this.numeroUnico, this.nombre, this.fechaNacimiento, this.ira);
        return estClonado;
    }
}

Como ya no se usará la clase Curso, entonces en la clase Aplicacion se tendrá el siguiente código:

public static void main(String args[]) throws ParseException {
        ArrayList<Estudiante> listaEstudiantes = new ArrayList<Estudiante>();
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        Calendar f1 = Calendar.getInstance();
        f1.setTime(sdf.parse("25-05-1993"));
        Estudiante e1 = new Estudiante("201210080", "Emily", f1, 29.3);
        listaEstudiantes.add(e1);
        Calendar f2 = Calendar.getInstance();
        f2.setTime(sdf.parse("15-12-1991"));
        Estudiante e2 = new Estudiante("201210180", "Edison", f2, 39.1);
        listaEstudiantes.add(e2);
        Calendar f3 = Calendar.getInstance();
        f3.setTime(sdf.parse("15-07-1994"));
        Estudiante e3 = new Estudiante("201010080", "Jenny", f3, 40.0);
        listaEstudiantes.add(e3);
        System.out.println("***************************ESTUDIANTES***************************");
        System.out.printf("\tNúmero único\tNombre\t\tEdad\t\t\tIRA\n");
        for (Estudiante e : listaEstudiantes) {
            System.out.println(e);
        }
        System.out.println("");
        System.out.println("");
        listaEstudiantes.add(e1.clone()); //Se clona el objeto 1 y se agrega a la lista
        listaEstudiantes.add(e3.clone()); //Se clona el objeto 2 y se agrega a la lista
        System.out.println("***************************ESTUDIANTES***************************");
        System.out.printf("\tNúmero único\tNombre\t\tEdad\t\t\tIRA\n");
        for (Estudiante e : listaEstudiantes) {
            System.out.println(e);
        }
//Cambiamos los valores para comprobar que los objetos clonados no sufrirán ningún cambio
        e1.setNombre("Alex");
        e3.setIra(100.45);
        System.out.println("***************************ESTUDIANTES***************************");
        System.out.printf("\tNúmero único\tNombre\t\tEdad\t\t\tIRA\n");
        for (Estudiante e : listaEstudiantes) {
            System.out.println(e);
        }
    }

El resultado de la ejecución es: 


Los objetos clonados no sufrieron cambios.




: