martes, 8 de diciembre de 2015

Lanzamiento de excepciones

Las excepciones son lanzadas de manera automática por las rutinas que han sido identificadas en la biblioteca de clases de las API de Java para este fin.
Pero  el  programador  puede  lanzar  dichas  excepciones  utilizando  la  palabra reservada throw.
El  siguiente ejemplo muestra como se lanza una excepcion por parte del programador
import javax.swing.*;
import java.lang.*;
public class ejemplo2{
    public static int x[ ]= new int[10];

Fundamentos de programación orientada a objetos con Java
    public static int getElement(int i) throws ArrayIndexOutOfBoundsException { // Avisa que
                                               // Una excepción puede ocurrir en el método
        if(i>x.length)
            throw new ArrayIndexOutOfBoundsException( );  // Lanza la excepción
        return x[i];
    }
        public static void main(String [ ] args){
               
            try{
                System.out.println(getElement(20));
            }
            catch (ArrayIndexOutOfBoundsException AE){
                System.err.println("Error indice fuera de rango");
            }
        }
}
Como  se  puede  observar  el  formato  para  lanzar  una  excepción  es  el siguiente:
throw   new claseException ( );
claseException es el nombre de la clase que tenemos que crear un objeto para lanzar la excepción.
La palabra throw requiere por fuerza un objeto Throwable o descendiente de el. El objeto que se cree y se lance con throw debe ser de la misma clase que espera alguna de las clausulas catch despues de la clausula try.

Excepciones mas comunes

Cada lenguaje define sus propias exceciones,  el  caso particular  de Java,
ofrece una jerarquia de clases para el  manejo de excepciones,  se inicia con la
clase java.lang.Throwable de la cual se desprenden las clases  java.lang.Error y
java.lang.Exception.
Cada paquete implementa las excepciones para manejar cuestiones propias
que ocurren en cada clase que conforman un paquete,  algunas excepciones se
muestran a continuación:

java.lang ArithmeticException
Ocurre   cuando   una   operación aritmetica   no   puede   ocurrir   por sobreflujo, división por cero, etc.

java.lang ArrayIndexOutOfBoundsException
Ocurre cuando se intenta acceder a  posiciones  fuera  del   limite  de un arreglo.

java.lang ClassNotFoundException
Ocurre   cuando   una   aplicación intenta  cargar   una  clase  y  no  la localiza.

java.lang NullPointerException
Ocurre cuando se intenta acceder a   un   elemento   de   un   arreglo cuando  no  se  ha  creado  o  a un objeto que tiene el valor de null.

java.lang NumberFormatException
 Ocurre   cuando   se   intenta convertir   de   una   cadena   a   un valor   numérico  y  no  esta   en  el
formato apropiado.

java.io EOFException
Ocurre   cuando   se   intenta   leer desde   un   archivo   o   desde   un flujo   de   entrada   cuando   se
encuentra en el fin del archivo.

java.io IOException
 Ocurre cuando una operacion de lectura/escritura   no   se   pudo llevar a cabo correctamente

Throw

Con la claúsula throws indicamos todas las excepciones que no serán manejadas
dentro del método, sino por el método que la llama. Estas excepciones podrán ser
errores del programa como los vistos anteriormente, o bien, generados de forma
explícita con throw.

 La sintáxis de throw es la siguiente:

throw <ObjetoThrowable>;

El <ObjetoThrowable> es un objeto de clase Throwable o alguna de sus
subclases. Tenemos dos opciones de obtener este objeto:
• Si estamos dentro de un bloque catch, el parámetro (<TipoExcepción>).
• Si estamos fuera de los bloques catch, dentro del código propiamente dicho
de un método, crearlo con el operador new.

Al ejecutarse una sentencia throw, la ejecución salta al bloque catch
correspondiente, de la misma forma que si se hubiera producido el error de forma
natural.

Ventajas:


• Una clase informa de las posibles situaciones anómalas de la clase.
• Esas excepciones tendrá que redefinir el método que llame a este método de forma
obligatoria. Esto nos permite decidir las acciones a tomar en caso de que se
produzcan. El método que llama, o cualquier otro por encima en la pila de llamadas.

Por ejemplo, el método "FileWriter" se ha definido:

 public FileWriter (String name) throws IOException {
  // ...
 }


Si utilizamos el método "FileWriter" definido así, deberemos capturar la
excepción "IOException" de forma obligatoria. Así podemos decidir lo que hacer en el
caso de que se produzca un error de ese tipo.

Programacion y Generalizacion

El <TipoExcepción> es un objeto que se instancia a partir de la clase correcta
(Throwable o alguna de sus subclases), justo en el momento de producirse el error, y
contiene información de la excepción producida.

Programación avanzada    
 En la estructura jerárquica de la librería de clases de Java, tenemos las clases que
implementan cada uno de los distintos tipos de error:

Java.lang.Throwable
  Exception
   RuntimeException
    ArithmeticException
    NullPointerException
    NumberFormatException
    ArrayIndexOutOfBoundsException
   ClassNotFoundException
   IOException
    EOFException
  Error

 La clase raíz es Throwable, la cual tiene dos subclases que clasifican los dos
grupos de tipos error posibles:

 Exception: son los errores habituales, capturables por el usuario. De esta
clase se derivan otras subclases, e incluso podemos derivar nosotros nuestras
propias clases.

 Error: son errores graves, en los que conviene no capturar su excepción y
dejar que aborte el programa de forma anormal. Suelen ser errores de
ejecución de la JVM.

Cuando se produce un error, se mira si hay una manejador para dicha excepción
en el método donde se ha producido. Si no se captura la excepción, se va retornando en
la pila de llamadas, hasta llegar a la función main() si no se hubiese capturado en
ninguna las funciones o métodos. Si en esta función tampoco se captura la excepción, se
ejecutará el manejador de excepciones por defecto, que consiste en abortar el
programa mostrando un mensaje significativo del error y el lugar donde se ha producido
(clase, método, número de línea, pila de llamadas, etc.).

 Cuando utilizamos las clases de Java (o nuestras), hay métodos que lanzan una
excepción (throw). Dependiendo del tipo de excepción estaremos obligados a capturar
la excepción generada o no. Por esto, debemos distinguir dos tipos de excepciones:

• Excepciones implícitas: no estamos obligados a capturarlas.
Son todas las de RuntimeException y Error.

• Excepciones explícitas: si estamos obligados a capturarlas.
Son ClassNotFoundException, IOException y EOFException.


Generación de errores
Programación avanzada    

 Otra posibilidad que tenemos en la gestión de errores es provocarlos de forma
explícita. Para ello utilizaremos las palabras clave: throw y throws.

 Vimos que la declaración de un método tenía la siguiente sintáxis:

[<Modif. método>] <TipoRetorno> <NombreMetodo> ( [<ListaParámetros>] ) [throws <Excepciones>]
{
 // Variables locales
 ...
 // Instrucciones o sentencias
 ...
 return (<Expresión>);
}


Excepciones en java

Cuando se produce algún error durante la ejecución de un programa, el intérprete
Java aborta su ejecución, mostrando un mensaje. Java dispone de unas sentencias para
poder capturar los errores en tiempo de ejecución, pudiendo nosotros decidir la acción a
realizar en el caso de que se produzca un error, y sin que se detenga la ejecución del
programa.

 Se trata de las sentencias de manejo de excepciones: try ... catch ... finally.

try {
<Bloque de sentencias a supervisar>
}
catch ( <TipoExcepcion> ) {
<Bloque de sentencias a ejecutar en caso de error>
}
finally {
<Bloque de sentencias a ejecutar en caso de error por defecto>
}

 La ventaja de estas sentencias es que separamos de forma explícita el código
que gestiona los errores del código del programa propiamente dicho, obteniendo un
código más claro que si utilizásemos sentencias de tipo: if, switch, etc. Además, el
código se ejecutará de forma más eficiente, ya que no tendremos que estar
continuamente comprobando condiciones que no son muy frecuentes o “imposibles”.

lunes, 9 de noviembre de 2015

Redefinición de Métodos en clases derivadas

Redefinicion de las clases derivadas

El lenguaje java permite redefinir miembros de la clase base en las clases derivadas, pero el compilador emite una advertencia cuando detecta una redefinición. Una advertencia (warning) es un mensaje del compilador acerca de un posible problema. Sin embargo, en este caso sí se genera código ejecutable (a diferencia del mensaje de error). Redefinición de campos. El siguiente ejemplo muestra cómo reutilizar los identificadores de los campos de la clase base en una clase derivada.
Ejemplo de redefinición de las clases derivadas
// Redef.cs : Ejemplifica la redefinición de campos en clases derivadas.
class Punto{
public int x;
public int y;
}
class Punto3D : Punto{
public int x ;

public int y ;

public int z ;
}
class Principal{
public static void Main( ) {
Punto a = new Punto( ); Punto3D b = new Punto3D( );
a.x = 100 ;
a.y = 200 ;
b.x = 300 ;

b.y = 400 ;

b.z = 500 ;
}
}

Referencia al objeto de la clase base

La jerarquía de clases que describen las figuras planas


Consideremos las figuras planas cerradas como el rectángulo, y el círculo. Tales figuras comparten características comunes como es la posición de la figura, de su centro, y el área de la figura, aunque el procedimiento para calcular dicha área sea completamente distinto. Podemos por tanto, diseñar una jerarquía de clases, tal que la clase base denominada Figura, tenga las características comunes y cada clase derivada las específicas. La relación jerárquica se muestra en la figura
La clase Figura es la que contiene las características comunes a dichas figuras concretas por tanto, no tiene forma ni tiene área. Esto lo expresamos declarando Figura como una clase abstracta, declarando la función miembro area abstract.
Las clases abstractas solamente se pueden usar como clases base para otras clases. No se pueden crear objetos pertenecientes a una clase abstracta. Sin embargo, se pueden declarar variables de dichas clases.
En el juego del ajedrez podemos definir una clase base denominada Pieza, con las características comunes a todas las piezas, como es su posición en el tablero, y derivar de ella las características específicas de cada pieza particular. Así pues, la clase Pieza será una clase abstracta con una funciónabstract denominada mover, y cada tipo de pieza definirá dicha función de acuerdo a las reglas de su movimiento sobre el tablero.
·                     La clase Figura
La definición de la clase abstracta Figura, contiene la posición x e y de la figura particular, de su centro, y la función area, que se va a definir en las clases derivadas para calcular el área de cada figura en particular.
public abstract class Figura {
    protected int x;
    protected int y;
    public Figura(int x, int y) {
        this.x=x;
        this.y=y;
    }
    public abstract double area();
}
·                     La clase Rectangulo
Las clases derivadas heredan los miembros dato x e de la clase base, y definen la función area, declarada abstract en la clase base Figura, ya que cada figura particular tiene una fórmula distinta para calcular su área. Por ejemplo, la clase derivada Rectangulo, tiene como datos, aparte de su posición (x, y) en el plano, sus dimensiones, es decir, su anchura ancho y altura alto.
class Rectangulo extends Figura{
    protected double ancho, alto;
    public Rectangulo(int x, int y, double ancho, double alto){
        super(x,y);
        this.ancho=ancho;
        this.alto=alto;
    }
    public double area(){
        return ancho*alto;
    }
}
La primera sentencia en el constructor de la clase derivada es una llamada al constructor de la clase base, para ello se emplea la palabra reservada super. El constructor de la clase derivada llama al constructor de la clase base y le pasa las coordenadas del punto x e y. Después inicializa sus miembros datoancho y alto.
En la definición de la función area, se calcula el área del rectángulo como producto de la anchura por la altura, y se devuelve el resultado
·                     La clase Circulo
class Circulo extends Figura{
    protected double radio;
    public Circulo(int x, int y, double radio){
        super(x,y);
        this.radio=radio;
    }
    public double area(){
        return Math.PI*radio*radio;
    }
}
Como vemos, la primera sentencia en el constructor de la clase derivada es una llamada al constructor de la clase base empleando la palabara reservadasuper. Posteriormente, se inicializa el miembro dato radio, de la clase derivada Circulo.
En la definición de la función area, se calcula el área del círculo mediante la conocida fórmula r2, o bien *r*r. La constante Math.PI es una aproximación decimal del número irracional .

Uso de la jerarquía de clases

Creamos un objeto c de la clase Circulo situado en el punto (0, 0) y de 5.5 unidades de radio. Calculamos y mostramos el valor de su área.
        Circulo c=new Circulo(0, 0, 5.5);
        System.out.println("Area del círculo "+c.area());
Creamos un objeto r de la clase Rectangulo situado en el punto (0, 0) y de dimensiones 5.5 de anchura y 2 unidades de largo. Calculamos y mostramos el valor de su área.
        Rectangulo r=new Rectangulo(0, 0, 5.5, 2.0);
        System.out.println("Area del rectángulo "+r.area());
Veamos ahora, una forma alternativa, guardamos el valor devuelto por newal crear objetos de las clases derivadas en una variable del tipo Figura(clase base).
        Figura f=new Circulo(0, 0, 5.5);
        System.out.println("Area del círculo "+f.area());
        f=new Rectangulo(0, 0, 5.5, 2.0);
        System.out.println("Area del rectángulo "+f.area());

Reutilización de miembros heredados

La re utilización de código se refiere al comportamiento y a las técnicas que garantizan que una parte o la totalidad de un programa informático existente se pueda emplear en la construcción de otro programa. De esta forma se aprovecha el trabajo anterior, se economiza tiempo, y se reduce la redundancia.
La manera más fácil de reutilizar código es copiarlo total o parcialmente desde el programa antiguo al programa en desarrollo. Pero es trabajoso mantener múltiples copias del mismo código, por lo que en general se elimina la redundancia dejando el código reusable en un único lugar, y llamándolo desde los diferentes programas. Este proceso se conoce como abstracción. La abstracción puede verse claramente en las bibliotecas de software, en las que se agrupan varias operaciones comunes a cierto dominio para facilitar el desarrollo de programas nuevos. Hay bibliotecas para convertir información entre diferentes formatos conocidos, acceder a dispositivos de almacenamiento externos, proporcionar una interfaz con otros programas, manipular información de manera conocida (como números, fechas, o cadenas de texto).
Para que el código existente se pueda reutilizar, debe definir alguna forma de comunicación o interfaz. Esto se puede dar por llamadas a una subrutina, a un objeto, o a una clase.
 
Como se ha comentado anteriormente la clase descendiente puede añadir sus propios atributos y métodos pero también puede sustituir u ocultar los heredados. En concreto:
1. Se puede declarar un nuevo atributo con el mismo identificador que uno heredado, quedando este atributo oculto. Esta técnica no es recomendable.
2. Se puede declarar un nuevo método de instancia con la misma cabecera que el de la clase ascendiente, lo que supone su sobreescritura. Por lo tanto, la sobreescritura o redefinición consiste en que métodos adicionales declarados en la clase descendiente con el mismo nombre, tipo de dato devuelto y número y tipo de parámetros sustituyen a los heredados.
3. Se puede declarar un nuevo método de clase con la misma cabecera que el de la clase ascendiente, lo que hace que éste quede oculto. Por lo tanto, los métodos de clase o estáticos (declarados como static) no pueden ser redefinidos.
4. Un método declarado con el modificador final tampoco puede ser redefinido por una clase derivada.
5. Se puede declarar un constructor de la subclase que llame al de la superclase de forma implícita o de mediante la palabra reservada super.
6. En general puede accederse a los métodos de la clase ascendiente que han sido redefinidos empleando la palabra reservada super delante del identificador del método. Este mecanismo sólo permite acceder al metodo perteneciente a la clase en el nivel inmediatamente superior de la jerarquía de clases.

Construyamos la clase Taxista.java con el siguiente código:
public class Taxista extends Persona {
private int nLicencia;
public void setNLicencia(int num){
nLicencia = num;
}
public int getLicencia(){
return nLicencia;
}
}
Y construyamos ArranqueTaxista.java:

public class ArranqueTaxista {
public static void main (String arg[]){
Taxista tax1 = new Taxista();
tax1.setNombre("Luis");
tax1.setEdad(50);
System.out.println( tax1.getNombre());
System.out.println(tax1.getEdad());
}
}
Ahora intentemos usar el constructor que existía en la clase Persona que recibia el nombre de la persona y vamos a usarlo para la clase Taxista. Para ello construyamos la clase ArranqueTaxista2.java:

public class ArranqueTaxista2 {
public static void main (String arg[]){
Taxista tax1 = new Taxista("Jose");
tax1.setEdad(50);
System.out.println( tax1.getNombre());
System.out.println(tax1.getEdad());
System.out.println(tax1.getNLicencia());
}
}
Se genera un error de compilación, debido a que los constructores no se heredan, sino que hay que definir nuestros propios constructores. Agreguemos en la clase Taxista los siguientes constructores:

public Taxista(int licencia){
super();
nLicencia = licencia;
}
public Taxista(String nombre,int licencia){
super(nombre);
nLicencia = licencia;
}
Ahora si podremos compilar y ejecutar la clase ArranqueTaxista2. La llamada al método super indica que estamos llamando a un constructor de la clase base (pensemos que un Taxista antes que Taxista es Persona y por tanto tiene sentido llamar al constructor de Persona antes que al de Taxista). Además gracias al número de parámetros de la llamada a super podemos especificar cuál de los constructores de la clase base queremos llamar.
En java se pueden emplear dos palabras clave: this y super. Como vimos en la unidad 1, this hace alusión a todo el objeto y super hace alusión a la parte heredada, por ello empleamos super para referenciar al constructor de la clase base.
Ahora vamos a agregar la función getNombre dentro de la clase Taxista, es decir, tenemos la misma función en Persona y en Taxista:

public String getNombre() {
return "Soy un taxista y me llamo: " + super.getNombre();
}

Compilamos Taxista y ejecutamos ArranqueTaxista2. Veremos que el mensaje que aparece en pantalla demuestra que la función getNombre llamada es la de del tipo real del objeto construido, en este caso la de la clase derivada que es Taxista.

Tambien apreciamos que para acceder al atributo nombre es necesario acceder al método getNombre de la clase base (y por ello emplear super).

En java los atributos y métodos de la clase base pueden cambiar su modificador de visibilidad dentro de la clase derivada, la siguiente tabla recoge dichos cambios:
Modificadores en la clase base:
public
private
protected
paquete

En la clase derivada se transforman en:
public
inaccesible
protected
paquete

Inaccesible significa que, a pesar de haber sido heredado, no hay permisos en la clase derivada para poder acceder a dicho elemento inaccesible, pero aún así, se pueden llamar a métodos de la clase base que si pueden acceder y modificar al elemento.
Recordemos que protected significa que es private, pero que al heredar no se hace inaccesible, es decir que desde la clase derivada se puede acceder.

Clase base y Clase derivada

Las clases pueden heredar de otra clase. Para conseguir esto, se coloca un signo de dos puntos después del nombre de la clase al declarar la clase y se denomina la clase de la cual se hereda (la clase base) después del signo de dos puntos, del modo siguiente:
public class A
{
    public A() { }
}
 
public class B : A
{
    public B() { }
}
La nueva clase (la clase derivada) obtiene todos los datos no privados y el comportamiento de la clase base, además de todos los demás datos y comportamientos que define para sí misma. La nueva clase tiene dos tipos efectivos: el tipo de la nueva clase y el tipo de la clase que hereda.
En el ejemplo anterior, la clase B es claramente B y A. Cuando se tiene acceso a un objeto B, se puede utilizar la operación de conversión de tipos para convertirlo en un objeto A. La conversión de tipos no cambia el objeto B, pero la vista del objeto B se restringe a los datos y comportamientos de A. Después de convertir un objeto B en un objeto A, es posible volver a convertir ese objeto A en un objeto B. No todas las instancias de A se pueden convertir en B, sólo aquellas que son realmente instancias de B. Si se tiene acceso a la clase B como tipo B, se obtienen los datos y comportamientos tanto de la clase A como de la clase B. La capacidad que tiene un objeto de representar más de un tipo se denomina polimorfismo.
Las estructuras no pueden heredar de otras estructuras o clases. Tanto las clases como las estructuras pueden heredar de una o más interfaces.
La palabra clave base se utiliza para obtener acceso a los miembros de la clase base desde una clase derivada:
  1. Realice una llamada a un método de la clase base reemplazada por otro método.
  2. Especifique a qué constructor de la clase base se debe llamar para crear instancias de la clase derivada.
El acceso a una clase base sólo se permite en un constructor, en un método de instancia o en un descriptor de acceso a una propiedad de instancia.
Es incorrecto utilizar la palabra clave base desde dentro de un método estático.
En este ejemplo, tanto la clase base, Person, como la clase derivada, Employee, poseen un método denominado Getinfo. Mediante la palabra clave base, se puede realizar una llamada al método Getinfo de la clase base desde la clase derivada.
// keywords_base.cs
// Accessing base class members
using System;
public class Person
{
    protected string ssn = "444-55-6666";
    protected string name = "John L. Malgraine";
 
    public virtual void GetInfo()
    {
        Console.WriteLine("Name: {0}", name);
        Console.WriteLine("SSN: {0}", ssn);
    }
}
class Employee : Person
{
    public string id = "ABC567EFG";
    public override void GetInfo()
    {
        // Calling the base class GetInfo method:
        base.GetInfo();
        Console.WriteLine("Employee ID: {0}", id);
    }
}
 
class TestClass
{
    static void Main()
    {
        Employee E = new Employee();
        E.GetInfo();
    }
}
Este ejemplo muestra cómo especificar el constructor de la clase base al que se realiza la llamada cuando se crean instancias de una clase derivada.
Cuando se crean instancias de una clase derivada.
// keywords_base2.cs
using System;
public class BaseClass
{
    int num;
 
    public BaseClass()
    {
        Console.WriteLine("in BaseClass()");
    }
 
    public BaseClass(int i)
    {
        num = i;
        Console.WriteLine("in BaseClass(int i)");
    }
 
    public int GetNum()
    {
        return num;
    }
}
 
public class DerivedClass : BaseClass
{
    // This constructor will call BaseClass.BaseClass()
    public DerivedClass() : base()
    {
    }
 
    // This constructor will call BaseClass.BaseClass(int i)
    public DerivedClass(int i) : base(i)
    {
    }
 
    static void Main()
    {
        DerivedClass md = new DerivedClass();
        DerivedClass md1 = new DerivedClass(1);
    }
}

Constructores y Destructores

Funciones Constructoras y Destructoras 


En los programas hay partes que requieren inicialización. Esta necesidad de inicialización es incluso más común cuando se está trabajando con objetos. Para tratar esta situación, C++ permite incluir una función constructora. A estas funciones se las llama automáticamente cada vez que se crea un objeto de esa clase. 

La función constructora debe tener el mismo nombre que la clase de la que es parte, no tienen tipo devuelto, es ilegal que un constructor tenga un tipo devuelto. Pero si es posible pasarle valores a modo de parámetros. 
Prototipo de la función: 
nombre_fucion(parámetros); 
Desarrollo de la función: 
nombre_calse::nombre_funcion(parámetros){ 
cuerpo; 
} 



El complemento de un constructor es la función destructora. A esta función se la llama automáticamente cuando se destruye el objeto. El nombre de las funciones destructoras debe ser el mismo que el de la clase a la que pertenece precedido del carácter ~ (alt+126). Los objetos de destruyen cuando se salen de ámbito cuando son locales y al salir del programa si son globales. Las funciones destructoras no devuelve tipo y tampoco pueden recibir parámetros. 

Técnicamente un constructor y un destructor se utilizan para inicializar y destruir los objetos, pero también se pueden utilizar para realizar cualquier otra operación. Sin embargo esto se considera un estilo de programación pobre. 
PROTOTIPO DE LA FUNCIÓN: 
~nombre_funcion(parámetros); 
DESARROLLO DE LA FUNCION: 
nombre_clase::nombre_funcion(){ 
cuerpo; 
}