miércoles, 16 de febrero de 2011

C4, 12/02/11: Bloque I.8: Clases de Utilidad

  • Introducción

  • A medida que vayas programando en Java te darás cuenta de que existe una gran cantidad de clases que resuelven muchos de los problemas que se te pueden presentar.


    Conocer la existencia de estas clases y su funcionalidad te ayudará a desarrollar rápidamente tus propias aplicaciones.


    En este capítulo se presentan algunas clases útiles que rápidamente incorporarás en tus aplicaciones, en particular vamos a estudiar los tipos genéricos, introducidos en Java SE5.



  1. Envolturas

  2. En Java existen dos tipos de datos: los tipos primitivos y los tipos referencia.


    La colecciones sólo pueden almacenar referencias.


    Entonces, ¿Cómo podemos utilizar las colecciones con los tipos primitivos?


    Tipo base primitivoEnvoltura
    voidjava.lang.Void
    booleanjava.lang.Boolean
    charjava.lang.Character
    bytejava.lang.Byte
    shortjava.lang.Short
    intjava.lang.Integer
    longjava.lang.Long
    floatjava.lang.Float
    doublejava.lang.Double

    Siempre es posible recuperar un tipo base a partir de su envoltura:



    Integer envolturaEntero = new Integer(15);
    Float envolturaReal = new Float(15.5f);
    int entero = envolturaEntero.intValue();
    float real = envolturaFloat.floatValue();

    Por otro lado, se pueden conseguir tipos numéricos primitivos a partir de String:



    String stringEntero = “505”;
    String stringReal = “1.234”;
    int entero = Integer.parseInt(stringEntero);
    float real = Float.parseFloat(stringReal);

    Muy útil al procesar los parámetros de entrada de la función main.


  3. Colecciones. Genéricos.

  4. Las colecciones son contenedores de objetos, como por ejemplo vectores, tablas de dispersión, listas,...





    InterfaceImplementación
    SetHashSet
    SortedSetTreeSet
    ListArrayList, LinkedList, Vector
    MapHashMap, HashTable
    SortedMapTreeMap

    Interface Collection



    public boolean add(Object o)
    public boolean remove(Object o)
    public boolean contains(Object o)
    public int size()
    public boolean isEmpty()
    public Iterator iterator()
    public Object[] toArray()
    public Object[] toArray(Object[] a)


    public void add(int posicion, Object o)
    public void remove(int posicion)
    public Object get(int posicion)
    public void set(int posicion, Object o)


    public class A { //Aunque no es indique explícitamente, esta clase es hija de "Object"
    protected int a = 0;
    public A() {};
    public A(int a) { this.a = a; }
    public void getA() {
    System.out.println("Clase A, valor: "+a);
    }
    }
    class B extends A { //Y por lo tanto esta también
    public B() { super(0); }
    public B(int a) { super(a); }
    public void getA() {
    System.out.println("Clase B, valor:"+a);
    }
    }


    public static void main(String args[]) { //¿Qué imprime?
    public static void main(String args[]) {
    ArrayList al = new ArrayList(); //Clase A, valor: 0
    for(int i = 0; i < 10; i += 2) //Clase A, valor: 2
    al.add(new A(i));//Objetos de tipo A //Clase A, valor: 4
    for(int i = 1; i < 10; i += 2) //Clase A, valor: 6
    al.add(new B(i));//Objetos de tipo B //Clase A, valor: 8
    A a = null; //Clase B, valor: 1
    Iterator it = al.iterator(); //Clase B, valor: 3
    while(it.hasNext() == true) { //Clase B, valor: 5
    a = (A)it.next(); //Objetos de tipo Object //Clase B, valor: 7
    a.getA(); //Clase B, valor: 9
    }
    }


    public class A {
    private int a;
    public A(int a) {this.a = a;}
    public void print() {
    System.out.println("Soy A y mi valor es: "+a);
    }
    }
    public class B {
    private int b;
    public B(int b) {this.b = b;}
    public void print() {
    System.out.println("Soy B y mi
    valor es: "+b);
    }
    }


    public static void main(String args[]) {
    ArrayList al = new ArrayList();
    for(int i = 0; i < i =" 5;" it =" al.iterator();" obj =" it.next();">

    public static void main(String args[]) { //Ahora Compila!!!
    ArrayList al = new ArrayList(); //Soy A y mi valor es : 0
    for(int i = 0; i < i =" 5;" it =" al.iterator();"> Error en tiempo
    A a; //de ejecución en "a=(A)it.next()"
    while(it.hasNext()) {
    a = (A)it.next();
    a.print();
    }
    }

    ¿Cómo solucionarlo?



    //Solucionado!!
    public static void main(String args[]) {
    ArrayList al = new ArrayList();
    for(int i = 0; i < i =" 5;" it =" al.iterator();" ob =" it.next();" a =" (A)ob;" b =" (B)ob;">

    Solución utilizando Interfaces



    public class A implements Imprime {
    private int a;
    public A(int a) {
    this.a = a;
    }
    public void print() {
    System.out.println("Soy A y mi valor es: "+a);
    }
    }

    public interface Imprime {
    public void print();
    }

    public class B implement Imprime {
    private int b;
    public B(int b) {
    this.b = b;
    }
    public void print() {
    System.out.println("Soy B y mi valor es: "+b);
    }
    }

    public static void main(String args[]) {
    ArrayList al = new ArrayList();
    for(int i = 0; i < 5; i++)
    al.add(new A(i));
    for(int i = 5; i < 10; i++)
    al.add(new B(i));
    Iterator it = al.iterator();
    Imprime imp;
    while(it.hasNext()) {
    imp = (Imprime) it.next();
    imp.print();
    }
    }
    //SOLUCIONADO!!

    Desde la versión del lenguaje SE%, se han introducido los tipos de datos genéricos, similares a los tipos de datos bastracto en C++



    ArrayList al = new ArrayList();
    al.add(1); // Se crea un Integer con «1».
    int i = al.get(0); // A partir de Integer se obtiene un int

    Se hace conversión entre tipos primitivos y envolturas:

    int <--> Integer

    float <--> Float

    boolean <--> Boolean

    ...


    También se ha introducido una nueva estructura de control, el bucle for-each, con una sintaxis compacta.


    • Sin genéricos:


    • ArrayList al = new ArrayList();
      for(int i = 0; i < 10; i++)
      al.add(new Integer(i));
      for(int i = 0; i < 10; i++)
      System.out.println(((Integer)al.get(i)).intValue);

    • Con genéricos:


    • ArrayList<Integer> al = new ArrayList<Integer>();
      for(int i = 0; i < 10; i++)
      al.add(i); // Conversión int --> Integer
      for(Integer i: al) // Bucle for-each
      System.out.println(i); // Conversión Integer --> int


    Además los genéricos evitan errores que antes sólo se detectarían en tiempo de ejecución: Antes de JAVA SE5



    ArrayList al = new ArrayList();
    al.add(new Integer(1));
    al.add(new Float(1.2));
    Iterator it = al.iterator();
    while(it.hasNext())
    Integer i = (Integer)it.next(); // Error en ejecución,
    //2º elemento Float


    ArrayList<Integer> al = new ArrayList<Integer>();
    al.add(new Integer(1));
    al.add(new Float(1.2)); // Error en compilación.

  5. Strings

  6. Los Strings almacenan cadenas de caracteres que NO se pueden modificar.



    String unaCadena = “Nombre “;
    String otraCadena = “Apellidos”;
    unaCadena = unaCadena + otraCadena; //El objeto String que contenía "Nombre" se pierde, y se crea
    // otro con el contenido "Nombre Apellidos" que es referenciado por "unCadena"

    Existe una gran cantidad de constructores para los Strings:



    String cadena = "Esto es una cadena.";
    char letras[]={"a", "b", "c"};
    String otraCadena = new String(letras);
    String pi = String.valueOf(3.141592);

    Y muchos métodos de utilidad



    public boolean equals(Object o)
    public int length()
    public String toLowerCase()
    public String toUpperCase()
    public String[] split(String s)
    String cadena = “Esto es una cadena”;
    String palabras[] = cadena.split(“ “);
    palabras[] = {“Esto”, “es”, “una”, “cadena”};

    • StringBuffer

    • Esta clase se comporta como un String pero se puede modificar. Es Thread safe


    • StringBuilder

    • Funcionalidad muy parecida a StringBuffer pero no es Thread safe.



  7. Matemáticas

    • Métodos de la clase java.lang.Math


    • public static [double|float|etc] abs(double|float|etc)
      public static double sin(double a)
      public static double cos(double a)
      public static double tan(double a)
      public static double log(double a)
      public static double sqrt(double a)
      public static double pow(double a, double b)
      public static double asin(double a)
      public static double acos(double a)
      public static double atan(double a)
      //Como se puede apreciar todos son "static"

    • Métodos de la clase java.util.Random


    • public boolean nextBoolean()
      public float nextFloat()
      public int nextInt()
      public int nextInt(int n)
      public long nextLong()
      public double nextDouble()
      public double nextGaussian()


  8. Entrada desde teclado

  9. La clase java.util.Scanner es una potente clase para leer datos desde streams de entrada, por ejemplo el teclado:



    Scanner escaner = new Scanner(System.in);
    escaner.useDelimiter(“\\n”);
    String cadena = escaner.next();
    int entero = escaner.nextInt();

    • Resumen

    • A medida que vayas conociendo más clases Java disminuirás el tiempo de codificación.


      En esta sesión se han presentado clases de uso inmediato en tus aplicaciones:


    • Envolturas.

    • Colecciones y Genéricos.

    • Cadenas de caracteres.

    • Matemáticas..


martes, 15 de febrero de 2011

C3, 11/02/11: Bloque I.7: Excepciones

  • Introducción

  • Las excepciones son situaciones anómalas que se producen durante la ejecución, como por ejemplo acceder a una posición de un vector inexistente.


    En algunos casos el error no se podrá gestionar, por ejemplo los producidos por la JVM, y en otros casos sí.


    Java proporciona un mecanismo para resolver este tipo de situaciones, y en el caso en que sea necesario establecer algún tipo de respuesta ante ellas. No podremos compilar el código a menos que lo hagamos, o indiquemos explícitamente que lo queremos hacer.




  1. Qué es una excepción

  2. Tipos de excepciones

  3. Cómo se gestiona una exepción


  4. try {
    readFromFile("esteFicheroNoExiste");
    }
    catch(FileNotFoundException e) {
    //Aquí tratamos esta excepción
    }
    catch(IOException e) {
    //Aquí tratamos esta otra
    }
    finally {
    //Aquí realizamos las tareas comunes.
    }


    void metodoLanzador() throws IOException { // "throws IOException" indica que hay excepciones que no se van a gestionar
    //...
    }

  5. Creación de excepciones propias


  6. public class MiExcepcion extends Exception {
    public MiExcepcion() {
    super("Texto de la excepcion");
    }
    }

    public class LanzaExcepcion {
    public void metodo() throws MiExcepcion { //Indica la posible excepción
    if(a < b) throw new MiExcepcion(); //Lanza la excepción
    }
    }


    public class OtraClase {
    public void metodo() {
    LanzaExcepcion le = new LanzaExcepcion();
    try {
    le.metodo();
    }
    catch (MiExcepcion e) {
    System.err.println(e.getMessage());
    }
    }
    }
    //Se atrapa como cualquier otra excepción. try/catch


  • Resumen

  • Las excepciones son el mecanismo de detección de errores en tiempo de ejecución en Java.


    Existen varios tipos de excepciones, los Error son
    excepciones irrecuperables. Las RunTimeException son excepciones que no es necesario atrapar.


    El resto de excepciones es necesario atraparlas y
    gestionarlas, o indicar explícitamente que no se van a atrapar con el uso de throws.



C3, 11/02/11: Bloque I.6: Herencia

  • Introducción

  • El comportamiento de una clase se puede modificar y extender para crear nuevas clases a partir de clases ya existentes


    A la clase original se le llama clase base o padre, mientras que a la que modifica y extiende las características se le llama clase heredada o hija. A este mecanismo se le conoce como el nombre de Herencia


    En Java, existe una nueva construcción que permite especificar qué métodos debe implementar una clase. Esta nueva construcción se llama <<interface>>.


    Además introduciremos las enumeraciones, nueva construcción en Java desde la versión 5.


    Finalmente veremos como agrupar las clases que están lógicamente relacionadas a través de los paquetes.



  1. Herencia


  2. public class Punto3D extends Punto { //"Punto3D" se extiende a la clase "Punto"
    protected float z; //Los nuevos atributos de la clase "Punto3D"
    public Punto3D() {
    super();
    this.z = 0.0f;
    }

    public Punto3D(float x, float y) {
    super(x, y);
    this.z = 0.0f;
    }

    public Punto3D(Punto unPunto) {
    super(unPunto.getX(), unPunto.getY());
    this.z = 0.0f;
    }
    // Como vemos en los 3 métodos siempre utilizamos "super()" al principio.



    public Punto3D(float x, float y, float z) {
    super(x, y);
    this.z = z;
    }

    public float getZ() { //Este método es nuevo
    return z;
    }
    //El resto de métodos se han sobrescrito
    public Punto inverso() {
    return new Punto3D(-x, -y, -z);
    }

    public String toString() {
    return "("+x+", "+y+", "+z+")";
    }

    public void print() {
    System.out.println("Coordenadas del punto "+this);
    }

    A una variable referencia a una clase A, siempre que se le puede asignar un objeto de cualquier clase hija.


    Al conrario nunca es posible y generará un error.




    //En es te código no hay errores ¿Qué se imprime?
    public class herenciaPunto3D {

    public static void main(String args[]) {
    Punto3D punto3D = new Punto3D(1.0f, 2.0f, 3.0f);
    Punto punto = unPunto3D;
    punto.print();
    punto.inverso().print();
    }
    }
    //Vinculación dinámica
    Coordenadas del punto (1.0, 2.0, 3.0)
    Coordenadas del punto (-1.0, -2.0, -3.0)


    Punto punto = new Punto(1.0f, 2.0f);
    Punto3D punto3D = unPunto;
    //¿Es esto posible?


  3. Sobrescritura de variables y métodos


  4. Los atributos y métodos de la clase padre siempre serán accesibles desde la hija a través de super.



    class Entero {
    public int dato;
    public void metodo() {};
    }
    class Real extends Entero {
    public float dato; //Sobrescribe a "dato" de la clase padre "Entero".
    public void metodo() {}; //Sobrescribe a "metodo" de la clase padre "Entero".
    }


  5. Sobrescritura de constructores


  6. //Error
    public class A {
    private int a;
    public A(int a) {
    this.a = a;
    }
    }

    public class B extends A {
    private int b;
    public B(int b) {
    this.b = b;
    }
    }

    public static void main (String args[]) {
    B b = new B(2);
    }

  7. Vinculación dinámica


  8. public class A {
    public A() {};
    public void metodo() {
    System.out.println("Clase A");
    }
    }
    class B extends A {
    public B() {};
    public void metodo() {
    System.out.println("Clase B");
    }
    }


    public static void main(String args[]) {
    System.out.println("Dame un numero:");
    int entero = Teclado.leeEntero();
    A a;
    if(entero > 100) a = new A();
    else a = new B();
    a.metodo();
    }


  9. El operador instanceof

  10. Como ya sabemos, a través de la herencia podemos utilizar referencias de una clase base sobre objetos de sus clases hijas, y al llamar a los métodos se vincularán los del objeto instanciado y no los que indique la referencia.


    Con el operador instanceof, podemos saber el tipo de objeto a través de una referencia.


    Este operador será de mucha utilidad cuando veamos las Colecciones



    public static void main(String args[]) {
    A a = new A();
    B b = new B();
    System.out.println("Es a instancia de A: "+(a instanceof A));
    System.out.println("Es b instancia de B: "+(b instanceof B));
    System.out.println("Es a instancia de B: "+(a instanceof B));
    System.out.println("Es b instancia de A: "+(b instanceof A));
    a = b;
    System.out.println("-----------------");
    System.out.println("Es a instancia de A: "+(a instanceof A));
    System.out.println("Es b instancia de B: "+(b instanceof B));
    System.out.println("Es a instancia de B: "+(a instanceof B));
    System.out.println("Es b instancia de A: "+(b instanceof A));
    }

  11. Clases abstractas


  12. public abstract class ClaseAbstracta {
    int a;
    public ClaseAbstracta() {};
    public abstract void metodo(); //Un método abstracto no se define
    public void noAbstracto() { // La clase puede tener otros métodos NO abstractos
    System.out.println(“Hola”);
    }
    }
    // No se pueden crear instancias de una clase abstracta

  13. Interfaces

  14. Como Java sólo permite herencia simple no podremos modelar el comportamiento de una clase mediante varias clases abstractas.


    Para poder añadir varios "comportamientis" a nuestra clase lo haremos a través de interfaces.


    Una clase sólo tiene una línea de herencia, pero puede implementar varios interfaces.


    Los interfaces son una generalización de las clases abstractas.



    interface SeDibuja {
    static final Color rojo = Color.RED;
    //No se implementa ningún método
    void dibujate();
    void ponColor(Color unColor);
    Color dameColor();
    }
    public class PuntoVisible implements SeDibuja {
    private Color color;
    // La clase implementa el interface, debe definir el método dibujate()
    public void dibujate() {
    System.out.println("Se dibuja el punto");
    }
    }



    public class CirculoVisible implements SeDibuja {
    public void dibujate() {
    System.out.println("Se dibuja el circulo");
    }
    }
    // En el programa principal
    PuntoVisible pv = new PuntoVisible();
    CirculoVisible cv = new CirculoVisible();
    SeDibuja spd = pv; //Utilizamos una referencia al interfaz
    spd.dibujate();
    spd = cv;
    spd.dibujate();

    Los interfaces también se pueden extender



    interface Vehiculo {
    public float getVelocidadMaxima();
    }
    interface Furgoneta extends Vehiculo { // <--- public float getCilindrada(); public int getPlazas; }

    Incluso un interfaz puede extender más de un padre.




    interface Vehiculo {
    interface Vehiculo {
    public float getVelocidadMaxima();
    }
    interface Imposiciones {
    public float getImpuestoCirculacion();
    }
    interface Furgoneta extends Vehiculo, Imposiciones {
    public float getCilindrada();
    public int getPlazas;
    }


  15. Enumeraciones

  16. Desde la Versión 5, se ha introducido en el lenguaje las enumeraciones


    Las enumeraciones son tipos de datos que permiten ser enumerados (se les puede asignar valores enteros)


    La definición de una enumeración es muy sencilla:



    enum Semana {LUNES, MARTES, MIERCOLES,
    JUEVES, VIERNES, SABADO, DOMINGO};
    Semana dia = Semana.LUNES

    Características:


    Las enumeraciones extienden implicitamente a clase "java.lang.Enum", por lo que no pueden extender a ninguna otra clase


    Sí que pueden implementar interfaces.


    Pueden implementar métodos como cualquier otra clase.


    No se pueden extender.


    Poseen dos métodos interesantes:


    • values(); que devuelve un array con los elementos de la enumeración.

    • ordinal(); que nos devuelve el orden del elemento dentro del array, empezando desde 0.


    Semana dia = Semana.LUNES;
    System.out.println("Día: " + dia + " orden: " + dia.ordinal());
    // Día: LUNES orden: 0


    public enum Semana {
    LUNES("Los lunes no me puedo levantar"),
    MARTES("Ni te cases ni te embarques"),
    MIERCOLES("Sin comentarios"),
    JUEVES("Siempre en medio"),
    VIERNES("Quedamos para salir"),
    SABADO("Volvemos a quedar"),
    DOMINGO("Mañana a clase de nuevo");
    private String comentario;

    // Constructor acceso de paquete o private.
    Semana(String comentario) {
    this.comentario = comentario;
    }
    public String getComentario() {
    return comentario;
    }
    public static void main(String args[]) {
    for(Semana dia: Semana.values())
    System.out.println(dia + " : " +
    dia.getComentario());
    }
    }

  17. Paquetes

  18. Los paquetes sirven para organizar jerárquicamente las clases


    Una clase se asigna a un paquete con la siguiente línea antes de la definición de la clase:



    package directorio.del.paquete;
    public class A {//...

    El fichero con los bytecodes de la clase A debe estar en un directorio directorio/del/paquete.


    Otra clase, la importa de este modo:



    import directorio.del.paquete.*;

    Puede acceder a...?
    misma claseSISISISI
    subclase del paqueteNOSISISI
    clase del paqueteNOSINOSI
    Subclase otro paqueteNONOSISI
    clase otro paqueteNONONOSI



  • Resumen

  • La herencia es el mecanismo utilizado en POO para crear nuevas clases a partir de clases ya existentes. En Java sólo existe herencia simple.


    Las clases hijas añaden nuevos atributos y métodos. Asimismo, pueden “ocultar” o sobrescribir atributos y métodos de la clase base.


    Una referencia a una clase base puede contener un objeto de cualquier clase hija, pero nunca al revés.


    La sobrescritura se resuelve en tiempo de ejecución mediante vinculación dinámica.


    Una clase base puede forzar que sus hijas definan algún método declarándolos como abstract. No se pueden crear instancias de una clase abstracta.


    La generalización de las clases abstractas son los interface. Un interface es una plantilla, declara todos los métodos que una clase que implemente el interface debe definir. Una clase puede implementar cuantos interfaces haga falta.


    Los paquetes son de utilidad para estructurar de un modo jerárquico las clase. Los paquetes imponen restricciones de acceso a sus clases.