Programación Orientada a Objetos ITSAVLerdo
3.8K views | +2 today
Follow
Programación Orientada a Objetos ITSAVLerdo
un blog sobre la Programacion orientada a objetos
Your new post is loading...
Your new post is loading...
Scooped by Cinthia Carrasco
Scoop.it!

Primera Unidad

Primera Unidad | Programación Orientada a Objetos ITSAVLerdo | Scoop.it


1.1 Elementos del modelo de objetos: clases, objetos, abstracción, modularidad, encapsulamiento, herencia y polimorfismo

¿Qué es una clase?


Antes que nada, un objeto es la instancia de una clase (o categoría). Usted y yo, por ejemplo, somos instancias de la clase Persona. Un objeto cuenta con una estructura, es decir atributos (propiedades) y acciones. Las acciones son todas las actividades que el objeto es capaz de realizar. Los atributos y acciones, en conjunto, se conocen como características o rasgos.
Como objetos de la clase Persona, usted y yo contamos con los siguientes atributos: altura, peso y edad (puede imaginar muchos mas). También realizamos las siguientes tareas: comer, dormir, leer, escribir, hablar, trabajar, etcetera. Si tuviéramos que crear un sistema que manejara información acerca de las personas (como una nomina o un sistema para el departamento de recursos humanos), sería muy probable que incorporáramos algunos de sus atributos y acciones en nuestro software.

En el mundo de la orientación a objetos, una clase tiene otro propósito además de la categorización. En realidad es una plantilla para fabricar objetos. Imagínelo como un molde de galletas que produce muchas galletas.

Piense en las cosas que le rodean (una idea demasiado amplia, pero piénselo de cualquier forma). Es probable que muchas de esas cosas tengan atributos (propiedades) y que realicen determinadas acciones. Podríamos imaginar cada una de esas acciones como un conjunto de tareas.

También se encontrara con que las cosas naturalmente se albergan en categorías (automóviles, mobiliario, lavadoras). A tales categorías las llamaremos clases. Una clase es una categoría o grupo de cosas que tienen atributos y acciones similares.

He aquí un ejemplo: cualquier cosa dentro de la clase Lavadoras tiene atributos como son la marca, el modelo, el número de serie y la capacidad. Entre las acciones de las cosas de esta clase se encuentran: y agregar ropa", “‘agregar detergente", "activarse" y "secar ropa".

La figura 1.1 le muestra un ejemplo de la notación del UML que captura los atributos y acciones de una lavadora. Un rectángulo es el símbolo que representa a la clase, y se divide en tres áreas. El área superior contiene el nombre, el área central contiene los atributos, y el área inferior las acciones. Un diagrama de clases está formado por varios rectángulos de este tipo conectados por líneas que muestran la manera en que las clases se relacionan entre sí.



¿Que es un objeto?

Un objeto es un elemento real o abstracto, que tiene un estado, un comportamiento y una identidad. Un objeto es, pues, una mesa, una silla, un alumno, una clase, etc., pues son elementos reales que se pueden comprender y están bien definidos. Un objeto también es un concepto abstracto como un elemento denominado «Ordenador» que es capaz de recibir un conjunto de números y los ordena ascendente o descendentemente.

En el mundo real, a menudo se encuentran muchos objetos individuales todos del mismo tipo. Puede haber miles de otras bicicletas en existencia, todos de la misma marca y modelo. Cada bicicleta se construyó desde el mismo conjunto de planos, por lo que contiene los mismos componentes. En términos orientados-objeto, se dice que la bicicleta es un ejemplo de la clase de objetos conocidos como las bicicletas. Una clase es el modelo de objetos individuales que se crean.

Las características que definen un objeto son tres: su estado, su comportamiento y su identidad.

Estado


Viene determinado para el conjunto de propiedades o atributos que tiene el objeto (que es su estructura estática), junto con los valores que pueden asumir cada uno de esos atributos (su estructura dinámica).


Véanse ambos ejemplos con datos concretos:


Objeto alumno "Luis Pérez Gómez".


• Estructura estática (su contenido no importa).


— Nombre y apellidos:
— Edad:
— Sexo:
— Dirección:
— Curso:
— Asignaturas:



• Estructura dinámica (en 1996).


— Nombre y apellidos: Luis Pérez Gómez
— Edad: 17
— Sexo: varón
— Dirección: calle del Pez, 24
— Curso: 3º BUP
— Asignaturas: Matemáticas, Física, Química, Inglés, Historia



• Estructura dinámica (en 1997).


— Nombre y apellidos: Luis Pérez Gómez
— Edad: 18
— Sexo: varón
— Dirección: calle Atocha, 18
— Curso: COU
— Asignaturas: Curso Completo



NOTA: El alumno Luis Pérez Gómez ha cambiado, entre 1996 y 1997, de edad, dirección, curso y asignaturas, porque es un objeto activo.

Objeto "Ordenador".


• Estructura estática


— Celdas de memoria: c1, c2, …, cn.
— Variable de estado: ve.



• Estructura dinámica


Si se le pide al objeto que ordene ascendentemente los números: 4, -5, 3, 10, -1, 2 su estructura dinámica va variando de la siguiene forma:



— Estado inicial: Los números se leen y se almacenan en las celdas.


c1 c2 c3 c4 c5 c6


4 -5 3 10 -1 2


ve=0


— Estado final ordenado: Los números han sido ordenados ascendentemente.


c1 c2 c3 c4 c5 c6


-5 -1 2 3 4 10


ve=1


NOTA: Se ha supuesto que la variable de estado (ve) del objeto «Ordenador» toma los valores 0, 1 ó 2, según que la información esté sin ordenar, ordenada ascendentemente u ordenada descendentemente.

El hecho de que un objeto tenga un estado implica que ocupa un espacio, sea en el mundo real o en la memoria de la computadora, exista durante un tiempo, cambie el valor de sus atributos, y sea creado y destruido.

Así, el objeto alumno «Luis Pérez Gómez» descrito anteriormente se crea cuando se le matricula en el colegio; existe como alumno durante toda su vida escolar; cambia sus datos al cambiar de curso o por otras circunstancias, y deja de ser alumno cuando sale del colegio.



Comportamiento


El comportamiento de un objeto viene determinado por la forma de actuar al recibir un mensaje para que realice una acción.
Un «mensaje» es una orden que se manda a un objeto para que realice una operación con un propósito específico.

Así, en el caso del objeto «Ordenador», se le podrían mandar los siguientes mensajes:


— «leer_números», para que leyera números enteros desde el teclado y los almacenara en las celdas de memoria: c1,c2,…,cn.


— «ordenar_ascendentemente», para que el contenido almacenado en c1,c2,…,cn, quedase ordenado ascendentemente.


— «ordenar_descendentemente», para obtener un contenido con orden descendente.


— «indicar_estado», para que especificara mediante la variable de estado ve si los números están sin ordenar (ve=0) ordenados ascendentemente (ve=1), u ordenados descendentemente (ve=2).


— «mostrar_números», para que visualizase por la pantalla de la computadora los números almacenados en las celdas de memoria c1,c2,…,cn.

Un mensaje viene definido por tres componentes:


— El objeto receptor del mensaje, es decir, al objeto que se envía el mensaje.


— El selector del mensaje, que es la acción que se quiere que realice el objeto.


— Los argumentos, que son los valores que se transmiten con el selector y que, en

muchos casos, pueden ser nulos.


Por ejemplo, Ordenador.Ordenar_ascendentemente(), es un mensaje que se envía al objeto receptor Ordenador, para que ordene ascendentemente los números (selector), y no se transmite ningún argumento. Mientras que los mensajes:

Luis_Perez_Gomez.Asignaturas(curso)


Luis_Perez_Gomez.Asignaturas(todas)


Señalan: el primero, que se desea conocer las asignaturas del curso en que Luis está

matriculado, y el segundo, que se desea conocer todas las asignaturas en que está

matriculado. En estos dos ejemplos, el argumento del selector (curso o todas) permite seleccionar unas asignaturas u otras.




Identidad


Se entiende por identidad de un objeto la propiedad característica que tiene ese objeto que le distingue de todos los demás. Realmente, es difícil encontrar un dato específico que permanentemente identifique al objeto.

Así, si se hace referencia a Luis Pérez Gómez, ¿se puede seleccionar algún dato que lo identifique durante toda su vida?:


— ¿Su nombre? - Lo puede cambiar en el Registro Civil.


— ¿Su edad? - Cambia continuamente.


— ¿Su DNI?, ¿Su sexo? - También pueden cambiar.


Pero es indudable que pasará el tiempo y Luis Pérez no perderá su identidad y se podrá diferenciar de todas las demás personas.

Si en la vida real es difícil identificar permanentemente un objeto que evoluciona, mucho más lo es en el mundo de la computadora. Normalmente se utiliza, como en la vida real, un nombre definido por el programador que lo identifique.

Así, en el caso del objeto anterior que lee datos y los ordena ascendente o descendentemente se le ha identificado con la palabra «Ordenador».

¿Que es Abstracción?


La abstracción se refiere a quitar las propiedades y acciones de un objeto para dejar solo aquellas que sean necesarias. ¿Qué significa esto último?
Diferentes tipos de problemas requieren distintas cantidades de información, aun si estos problemas pertenecen a un área en común.
Supongamos una lavadora a la cual en la primera fase le definimos los siguientes atributos: marca, modelo, número de serie y capacidad.
En una segunda fase de la creación de la clase Lavadora, se podrían agregar más atributos y acciones que en la primera fase.
¿Vale la pena?
Valdría la pena si usted pertenece al equipo de desarrollo que generara finalmente una aplicación que simule con exactitud lo que hace una lavadora. Un programa de este tipo
(que podría ser muy útil para los ingenieros de diseño que actualmente estén trabajando en el diseño de una lavadora) deberá ser tan completo que permita obtener predicciones exactas respecto a lo que ocurriría cuando se fabrique la lavadora, funcione a toda su capacidad y lave la ropa. De hecho, para este caso podrá quitar el atributo del número de serie, dado que posiblemente no será de mucha ayuda.
Por otra parte, si va a generar un software que haga un seguimiento de las transacciones en una lavandería que cuente con diversas lavadoras, posiblemente no valdría la pena.
En este programa no necesitaré todos los atributos detallados y operaciones del párrafo anterior, no obstante, quizá necesite incluir el número de serie de cada objeto Lavadora.
En cualquier caso, con lo que se quedará luego de tomar su decisión respecto a lo que incluiré o desecharé, será una abstracción de una lavadora.

Modularidad

En programación modular, y más específicamente en programación orientada a objetos, se denomina Modularidad a la propiedad que permite subdividir una aplicación en partes más pequeñas (llamadas módulos), cada una de las cuales debe ser tan independiente como sea posible de la aplicación en sí y de las restantes partes.
Estos módulos que se puedan compilar por separado, pero que tienen conexiones con otros módulos.
Al igual que la encapsulación, los lenguajes soportan la Modularidad de diversas formas.
Según Bertrand Meyer "El acto de particionar un programa en componentes individuales para reducir su complejidad en algún grado. . . . A pesar de particionar un programa es útil por esta razón, una justificación más poderosa para particionar un programa es que crea una serie de límites bien definidos y documentados en el programa. Estos límites, o interfaces, son muy valiosos en la comprensión del programa"
Por su parte Barbara Liskov establece que "popularización" consiste en dividir un programa en módulos que pueden ser compilados de forma separada, pero que tienen conexiones con otros módulos"

Encapsulamiento


Al hablar de los objetos, es importante comentar el concepto de encapsulación. Se dice que un objeto está encapsulado (literalmente, está dentro de una cápsula) cuando está protegido del acceso indiscriminado de cualquier persona.

Así, cuando se tiene en las manos un televisor, se ve que se puede encender o apagar, poner la emisora que más guste, aumentar o disminuir el volumen, pero no se puede mover físicamente el dial ( esto se realiza con un mando), ni tocar el indicador de encendido, ni acceder a otras cosas que están dentro del televisor. Esto último lo debe tocar un profesional. Por ello, se dice que:

— El dial, el indicador de encendido y la circuitería están encapsuladas.

— Los mandos de sintonía, volumen, encendido/apagado, etc., no están encapsulados y son de acceso normal para todos los usuarios del transistor.

Resumiendo, la encapsulación es el proceso que aplica el diseñador de un objeto para ocultar aquellos detalles del objeto que no son específicamente necesarios para su uso. A la encapsulación se le denomina también «ocultamiento de información».

Así, en el ejemplo del objeto «Ordenador», parece claro que deberían estar encapsuladas la celdas de memoria c1,c2,…,cn; y la variable de estado ve, ya que el usuario que maneja este objeto no necesita acceder directamente a estos datos. Mientras que no deberían estar encapsuladas las operaciones que realiza: «leer_números», «ordenar_ascendentemente», …, «mostrar_números».

Por lo tanto, un objeto, que es una unidad indivisible, tiene una parte interna que no es accesible al usuario y una parte externa que sí que es accesible. A esta parte accesible se le llama la interfaz (o protocolo) del objeto y lo constituye el conjunto de servicios que proporciona el objeto. Es realmente mediante esta interfaz como el usuario maneja el objeto.

La interfaz del televisor son el interruptor de encendido/apagado, los mandos de sintonía, volumen,…; todos ellos, elementos que permiten su manejo.

¿Cuál es la importancia de esto? En el mundo del software, el encapsulamiento permite reducir el potencial de errores que pudieran ocurrir. En un sistema que consta de objetos, éstos dependen unos de otros en diversas formas. Si uno de ellos falla y los especialistas de software tienen que modificarlo de alguna forma, el ocultar sus operaciones de otros objetos significara que tal vez no será necesario modificar los demás objetos

En el mundo real, también vera la importancia del encapsulamiento en los objetos con los que trabaje. Por ejemplo, el monitor de su computadora, en cierto sentido, oculta sus operaciones de la CPU, es decir, si algo falla en su monitor, lo reparara o lo reemplazaré; pero es muy probable que no tenga que reparar o reemplazar la CPU al mismo tiempo que el monitor.

Ya que estamos en el tema, existe un concepto relacionado. Un objeto oculta lo que hace a otros objetos y al mundo exterior, por lo cual al encapsulamiento también se le conoce como ocultamiento de la información. Pero un objeto tiene que presentar un "rostro" al mundo exterior para poder iniciar sus operaciones.
Por ejemplo, la televisión tiene diversos botones y perillas en si misma o en el control remoto. Una lavadora tiene diversas perillas que le permiten establecer los niveles de temperatura y agua. Los botones y perillas de la televisión y de la lavadora se conocen como interfaces.

En el mundo real, también vera la importancia del encapsulamiento en los objetos con los que trabaje. Por ejemplo, el monitor de su computadora, en cierto sentido, oculta sus operaciones de la CPU, es decir, si algo falla en su monitor, lo reparara o lo reemplazaré; pero es muy probable que no tenga que reparar o reemplazar la CPU al mismo tiempo que el monitor.

Herencia

Como ya se menciono anteriormente, una clase es una categoría de objetos (y en el mundo del software, una planilla sirve para crear otros objetos). Un objeto es una instancia de una clase. Esta idea tiene una consecuencia importante como instancia de una clase, un objeto tiene todas las características de la clase de la que proviene. A este se le conoce como herencia. No importa qué atributos y acciones decida usar de la clase En el ejemplo de la Lavadora, cada objeto de la clase heredara dichos atributos y operaciones.
Un objeto no solo hereda de una clase, sine que una clase también puede heredar de otra. Las lavadoras, refrigeradores, hornos de microondas, tostadores, lavaplatos, radios, licuadoras y planchas son clases y forman parte de una clase más genérica llamada;
Electrodomésticos. Un electrodoméstico cuenta con los atributos de interruptor y cable eléctrico, y las operaciones de encendido y apagado. Cada una de las clases Electrodoméstico heredara los mismos atributos; por ello, si sabe que algo es un electrodoméstico, de inmediato sabré que cuenta con los atributos y acciones de la clase Electrodoméstico.

Otra forma de explicarle es que la lavadero, refrigerador, home de microondas y cosas por el estilo son subclases de la clase Electrodoméstico. Podemos decir que la clase Electrodoméstico es una superclase de todas las demás. La figura 2.3 le muestra la relación de superclase y subclase,

La herencia no tiene por qué terminar aquí. Por ejemplo, Electrodoméstico es una subclase de Artículos del hogar, como le muestra la figura 2.4. Otra de las subclases de
Artículos del hogar podría ser Mobiliario, que tendrá sus propias subclases.

Ejemplo de la herencia
Diferentes tipos de objetos a menudo tienen una cierta cantidad en común entre sí. Las bicicletas de montaña, bicicletas de carretera y bicicletas tándem, por ejemplo, todos comparten las características de las bicicletas (velocidad actual, cadencia de pedaleo actual, equipo actual). Sin embargo, cada uno también define características adicionales que las hacen diferentes: bicicletas tándem tienen dos asientos y dos juegos de manillares, las bicicletas de carretera tienen manillar gota; algunas bicicletas de montaña tienen un anillo de las cadenas adicionales, dándoles una relación de transmisión más baja.
Programación orientada a objetos permite que las clases hereden de uso general del estado y el comportamiento de otras clases. En este ejemplo, la bicicleta se convierte en la superclase de BTT , RoadBike y TandemBike . En el lenguaje de programación Java, cada clase se le permite tener una superclase directa, y cada superclase tiene el potencial para un número ilimitado de las subclases :
Una jerarquía de clases de bicicleta.

La sintaxis para crear una subclase es simple. Al comienzo de su declaración de la clase, utilice la extiende palabra clave, seguido por el nombre de la clase que hereda de:



extends Bicycle {

// new fields and methods defining a mountain bike would go here

}



Esto da BTT todos los mismos campos y métodos de bicicletas , pero permite su código para centrarse exclusivamente en las características que lo hacen único. Esto hace que el código para que sus clases sean fáciles de leer. Sin embargo, debe tener cuidado de documentar apropiadamente el estado y el comportamiento que cada superclase define, ya que el código no aparecerá en el archivo de código fuente de cada subclase.

Polimorfismo

En ocasiones una operación tiene el mismo nombre en diferentes clases. Por ejemplo, podrá abrir una puerta, una ventana, un periódico, un regalo o una cuenta de banco, en cada uno de estos casos, realizara una operación diferente. En la orientación a objetos, cada clase "sabe" como realizar tal operación. Esto es el polimorfismo (vea la figura 2,5).

Por ejemplo, podemos crear dos clases distintas: Pez y Ave que heredan de la superclase Animal. La clase Animal tiene el método abstracto mover que se implementa de forma distinta en cada una de las subclases (peces y aves se mueven de forma distinta).
El concepto de polimorfismo se puede aplicar tanto a funciones como a tipos de datos. Así nacen los conceptos de funciones polimórficas y tipos polimórficos. Las primeras son aquellas funciones que pueden evaluarse o ser aplicadas a diferentes tipos de datos de forma indistinta; los tipos polimórficos, por su parte, son aquellos tipos de datos que contienen al menos un elemento cuyo tipo no está especificado.




1.2 Lenguaje de modelado unificado: diagrama de clases



Un diagrama de clases es un tipo de diagrama estático que describe la estructura de un sistema mostrando sus clases, atributos y las relaciones entre ellos. Los diagramas de clases son utilizados durante el proceso de análisis y diseño de los sistemas, donde se crea el diseño conceptual de la información que se manejará en el sistema, y los componentes que se encargaran del funcionamiento y la relación entre uno y otro.
Representación de: - Requerimientos en entidades y actuaciones. - La arquitectura conceptual de un dominio - Soluciones de diseño en una arquitectura - Componentes de software orientados a objetos.

Propiedades también llamados atributos o características, son valores que corresponden a un objeto, como color, material, cantidad, ubicación. Generalmente se conoce como la información detallada del objeto. Suponiendo que el objeto es una puerta, sus propiedades serían: la marca, tamaño, color y peso.

Operaciones comúnmente llamados métodos, son aquellas actividades o verbos que se pueden realizar con/para este objeto, como por ejemplo abrir, cerrar, buscar, cancelar, acreditar, cargar. De la misma manera que el nombre de un atributo, el nombre de una operación se escribe con minúsculas si consta de una sola palabra. Si el nombre contiene más de una palabra, cada palabra será unida a la anterior y comenzará con una letra mayúscula, a excepción de la primera palabra que comenzará en minúscula. Por ejemplo: abrirPuerta, cerrarPuerta, buscarPuerta, etc.
Interfaz es un conjunto de operaciones que permiten a un objeto comportarse de cierta manera, por lo que define los requerimientos mínimos del objeto. Hace referencia a polimorfismo.

Herencia se define como la reutilización de un objeto padre ya definido para poder extender la funcionalidad en un objeto hijo. Los objetos hijos heredan todas las operaciones y/o propiedades de un objeto padre. Por ejemplo: Una persona puede especializarse en Proveedores, Acreedores, Clientes, Accionistas, Empleados; todos comparten datos básicos como una persona, pero además cada uno tendrá información adicional que depende del tipo de persona, como saldo del cliente, total de inversión del accionista, salario del empleado, etc.
Al diseñar una clase se debe pensar en cómo se puede identificar un objeto real, como una persona, un transporte, un documento o un paquete. Estos ejemplos de clases de objetos reales, es sobre lo que un sistema se diseña. Durante el proceso del diseño de las clases se toman las propiedades que identifican como único al objeto y otras propiedades adicionales como datos que corresponden al objeto. Con los siguientes ejemplos se definen tres objetos que se incluyen en un diagrama de clases:

Ejemplo 1: Una persona tiene número de documento de identificación, nombres, apellidos, fecha de nacimiento, género, dirección postal, posiblemente también tenga número de teléfono de casa, del móvil, FAX y correo electrónico.

Ejemplo 2: Un sistema informático puede permitir administrar la cuenta bancaria de una persona, por lo que tendrá un número de cuenta, número de identificación del propietario de la cuenta, saldo actual, moneda en la que se maneja la cuenta.

Ejemplo 3: Otro objeto pueden ser "Manejo de Cuenta", dónde las operaciones bancarias de una cuenta (como en el ejemplo 2) se manejarán realizando diferentes operaciones que en el diagrama de clases de balurdes sólo se representan como operaciones, que pueden ser:


  • Abrir
  • Cerrar
  • Depósito
  • Retiro
  • Acreditar Inerese


Estos ejemplos constituyen diferentes clases de objetos que tienen propiedades y/u operaciones que contienen un contexto y un dominio, los primeros dos ejemplos son clases de datos y el tercero clase de lógica de negocio, dependiendo de quién diseñe el sistema se pueden unir los datos con las operaciones.
El diagrama de clases incluye mucha más información como la relación entre un objeto y otro, la herencia de propiedades de otro objeto, conjuntos de operaciones/propiedades que son implementadas para una interfaz gráfica.

more...
No comment yet.
Scooped by Cinthia Carrasco
Scoop.it!

Tercera Unidad

Tercera Unidad | Programación Orientada a Objetos ITSAVLerdo | Scoop.it

3.1 Definición: clase base, clase derivada


La clase base


Vamos a poner un ejemplo del segundo tipo, que simule la utilización de liberías de clases para crear un interfaz gráfico de usuario como Windows 3.1 o Windows 95.
Supongamos que tenemos una clase que describe la conducta de una ventana muy simple, aquella que no dispone de título en la parte superior, por tanto no puede desplazarse, pero si cambiar de tamaño actuando con el ratón en los bordes derecho e inferior.
La clase Ventana tendrá los siguientes miembros dato: la posición x e y de la ventana, de su esquina superior izquierda y las dimensiones de la ventana: ancho y alto.

package ventana;

public class Ventana {
protected int x;
protected int y;
protected int ancho;
protected int alto;

public Ventana(int x, int y, int ancho, int alto) {
this.x=x;
this.y=y;
this.ancho=ancho;
this.alto=alto;
}
public void mostrar(){
System.out.println("posición : x="+x+", y="+y);
System.out.println("dimensiones : w="+ancho+", h="+alto);
}
public void cambiarDimensiones(int dw, int dh){
ancho+=dw;
alto+=dh;
}
}



La clase derivada

Incrementamos la funcionalidad de la clase Ventana definiendo una clase derivada denominada VentanaTitulo. Los objetos de dicha clase tendrán todas las características de los objetos de la clase base, pero además tendrán un título, y se podrán desplazar (se simula el desplazamiento de una ventana con el ratón).

La clase derivada heredará los miembros dato de la clase base y las funciones miembro, y tendrá un miembro dato más, el título de la ventana.

public class VentanaTitulo extends Ventana{

protected String titulo;

public VentanaTitulo(int x, int y, int w, int h, String nombre)
{
super(x, y, w, h);
titulo=nombre;
}

extends es la palabra reservada que indica que la clase VentanaTitulo deriva, o es una subclase, de la clase Ventana. La primera sentencia del constructor de la clase derivada es una llamada al constructor de la clase base mediante la palabra reservada super. La llamada super (x, y, w, h);
En la clase derivada se define una función que tiene el mismo nombre y los mismos parámetros que la de la clase base. Se dice que redefinimos la función mostrar en la clase derivada. La función miembro mostrar de la clase derivada VentanaTitulo hace una llamada a la función mostrar de la clase base Ventana, mediante super.mostrar();.

3.2 Clasificación. Herencia simple, herencia múltiple.



• 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.
¿Existe la herencia múltiple en Java? ¿Por qué?

Objetivo: fortalecer los conceptos de clases, métodos, propiedades o atributos, herencia, constructores y acerca de los métodos Get y Set. Todo esto con ayuda del programa realizado en la guía anterior con nuestro “Silabario para programadores”. El trabajo estructurado de la semana pasada ahora lo traslademos a una aplicación, siempre en el ambiente consola, en la cual definamos con un alto grado de encapsulamiento, las clases que harán posible la realización de la aplicación y llevarán definida todo el funcionamiento, o lo que es mismo, la capa de negocios del programa.

El ejemplo es sencillo. El Silabario lo que realiza es una serie de operaciones básicas que resuelven 4 tipos de problemas distintos: El factorial de número, la tabla de multiplicar de un número, la clasificación de la edad del usuario y la elección de la estación del año favorita del usuario. El silabario además, tiene la característica que el programador escogerá la sentencia o instrucción básica que brinde la solución más sencilla y óptima para cada uno de los problemas.

Para efectos de esta práctica, y porque creo que es la mejor manera de poder apreciar las clases y objetos de este ejercicio, definiremos cada clase como una clase “Operación”, que es la que facilitará y tendrá las herramientas necesarias para efectuar la resolución de cada uno de los problemas.

Un objeto operación necesita de propiedades o atributos. Una operación necesita de operadores, uno, dos ó más. Es por eso que definiremos dos atributos para realizar dichas operaciones. Con dos bastarán para este ejercicio.
Los métodos de esta clase son muy variados. Cada una de las operaciones realizará uno diferente, por lo tanto no cabe dentro de la percepción de un objeto “Operación” básico, la definición de cada uno de los métodos.
Los métodos que sí se necesitarían son los populares métodos GET y SET, que nos sirven para leer y cambiar los valores de una propiedad específica. Como hemos definido propiedades, éstas necesitan de sus getters y setters. La clase de una Operación Básica para el silabario quedará así:


public class operacionBase {

protected int operador;

public operacionBase(){
this.operador=0;
}

public void setOperador(int o){
this.operador=o;
}

public int getOperador(){
return this.operador;
}
}



Declaramos la propiedad con visibilidad protected por motivos de seguridad, para que solamente los miembros de esa clase y los que heredan de ella, es decir las subclases, puedan accesar a estos atributos.

Como hemos definido ya una clase base, ahora podremos definir el resto de clases que podrán heredar de la clase base. Cabe destacar que no siempre se podrá hacer una clase base y con respecto a esta empezar a heredarles a otras. Esto depende de la naturaleza de cada aplicación, y de la manera de cómo el programador diseñe su capa de negocios.

Para realizar la clase que nos devuelva el factorial de un número, el programador puede escoger la instrucción While. Por lo tanto el programador debe desarrollar el método que reciba como parámetro el número del que se desee el factorial y que devuelva el resultado esperado. Heredando de la clase base, tenemos ya garantizados los atributos y métodos propios de la misma, por lo tanto, la clase para realizar el factorial del número podría quedar así:

public class operacionFactorial extends operacionBase{

public operacionFactorial(){
super();
}

public int devolverFactorial(){
int factorial=1;
int cont=1;

while (cont <= this.operador) { factorial *= cont; cont++; } return factorial;
}
}



El diagrama UML nos ayudará a comprender mejor la herencia y estructura de estas clases:

Como puede observar el programador, se utiliza la propiedad “operador” cuya definición pertenece a la clase base. Sin embargo, como la clase “operacionFactorial” hereda todos los atributos y métodos de la clase básica, podemos hacer un llamado a dicha propiedad con la ayuda de la sentencia “this”.

3.3 Reutilización de miembros heredados.

La reutilizació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.

Practicas:
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 .

3.4 Referencia al objeto de la clase base

La jerarquía de clases que describen las figuras planas
figura: Figura.java, FiguraApp.java
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ón abstract 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 y 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 dato ancho 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 reservada super. 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 new al crear objetos de las clases derivadas en una variable f 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());

3.5 Constructores y destructores en clases derivadas.


Constructores en clases derivadas.


Al instanciar objetos de clases derivadas se inicia una cadena de invocaciones a constructores en las cuales el constructor de la clase derivada, antes de realizar sus propias tareas, invoca (ya sea implícita o explícitamente) al constructor de su clase base. Similarmente, si la clase base fue derivada de otra clase, el constructor de la clase base debe invocar al constructor de la clase ubicada en el siguiente nivel superior de la jerarquía, y así sucesivamente. El último constructor invocado en la cadena es el constructor de la clase Object, cuyo cuerpo se ejecuta primero. El cuerpo del constructor de la clase derivada se ejecuta al final. El constructor de cada clase base inicializa las variables de instancia que el objeto de la clase derivada hereda.

Destructores en clases derivadas


Cuando remueve de la memoria un objeto de una clase derivada, el recolector de basura invoca al destructor del objeto. Esto inicia una cadena de invocaciones a destructores, en donde el destructor de la clase derivada y los destructores de las clases bases directas e indirectas se ejecutan en orden inverso al que se ejecutaron los constructores, esto es, primero se ejecuta el destructor de la clase derivada y al final se ejecuta el destructor de la clase base ubicada en el nivel superior de la jerarquía. La ejecución de los destructores debe liberar todos los recursos que el objeto adquirió, antes de que el recolector de basura reclame la memoria de ese objeto. Cuando el recolector de basura invoca al destructor de un objeto de una clase derivada, ese destructor realiza su tarea y después invoca al destructor de la clase base. El proceso se repite hasta que se invoca al destructor de la clase Object.

Ejemplo:
// Destruct Derivadas?.cs :
Destructores en clases derivadas. using C = System.Console;
class Animal { ~ Animal( )
{ C.Write Line?(“Muere mi parte Animal …”); } }
class Mamífero : Animal { ~ Mamífero( )
{ C.Write Line(“Muere mi parte Mamífero …”); } }
class Perro : Mamífero { ~ Perro( )
{ C.Write Line(“Muere mi parte Perro …”); } }
public class Principal { static void Main( ) { Perro Fido = new Perro ( ); } }

3.6 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 ;
}
}

more...
No comment yet.
Scooped by Cinthia Carrasco
Scoop.it!

Quinta Unidad

Quinta Unidad | Programación Orientada a Objetos ITSAVLerdo | Scoop.it


Definiciòn



El control de flujo en un programa Java puede hacerse mediante las ya conocidas sentencias estructuradas (if, while, return). Pero Java va mucho más allá, mediante una técnica de programación denominada gestión de excepciones.
Mediante las excepciones se podrá evitar repetir continuamente código, en busca de un posible error, y avisar a otros objetos de una condición anormal de ejecución durante un programa.
Durante este capítulo estudiaremos la gestión de excepciones y errores, sin pretender profundizar demasiado, pero sí fijando la base conceptual de lo que este modo de programación supone.
Mediante la gestión de excepciones se prescindirá de sentencias de control de errores del tipo:
if ( error == true )
return ERROR;
Las excepciones señalan errores o situaciones poco habituales en la ejecución de un programa, por ejemplo una división de un valor entre cero, un intento de acceso a un String declarado, pero no instanciado, etc.
Habitualmente, en programación, se incluyen tantas instrucciones condicionales como sea necesario para conseguir que una aplicación sea robusta, de esta manera, por ejemplo, en cada división de un valor entre una v ariable, antes se comprueba que el denominador no sea cero:

Denominador = 
if (Denominador != 0) {
Numerador = 
Resultado = Numerador / Denominador;
}
else
System.out.println (“No se puede realizar la división”);



try {
//Codigo donde puede ocurrir un error
}
catch (ExcepcionA ex) { // Que se va a hacer en caso que
se lanze una Excepcion A }
...
catch (ExcepcionZ ex) { // Que se va a hacer en caso que
se lanze una Excepcion Z }

Mediante las excepciones se podrá evitar repetir continuamente código, en busca de un posible error, y avisar a otros objetos de una condición anormal de ejecución durante un programa.

Las excepciones señalan errores o situaciones poco habituales en la ejecución de un programa, por ejemplo una división de un valor entre cero, un intento de acceso a un String declarado, pero no instanciado, etc.

Ejemplo :

import java.util.Scanner;
import java.util.InputMismatchException;
public class usodeExcepciones {
public static int cociente (int numerador, int denominador) throws ArithmeticException{
return numerador/denominador;
}
public static void main(String[] args) {
Scanner explorador = new Scanner(System.in);
boolean continuarCiclo=true;
do{
try{
System.out.print("Introduce un numero entero= ");
int numerador = explorador.nextInt();
System.out.print("Introduce un denominador entero= ");
int denominador = explorador.nextInt();
int resultado = cociente (numerador, denominador);
System.out.printf("Resultado de %d / %d = %d", numerador, denominador, resultado);
System.out.println();
continuarCiclo=false;
//fin del bloque try
}
catch(InputMismatchException objError){
System.err.printf("Exception: %s\n", objError);
explorador.nextLine();
System.out.println("Debe de introducir valores enteros. Intente de nuevo");
}
catch(ArithmeticException objaritmetico){
System.out.printf("Exception: %s\n", objaritmetico);
System.out.println("Cero es un denominador invalido. Intente de nuevo");
}
}while (continuarCiclo=true);
}
}



5.2 TIPOS DE EXCEPCIONES

Existen varios tipos fundamentales de excepciones:

• Error: Excepciones que indican problemas muy graves, que suelen ser no recuperables y no deben casi nunca ser capturadas.
• Exception: Excepciones no definitivas, pero que se detectan fuera del tiempo de ejecución.
• RuntimeException: Excepciones que se dan durante la ejecución del programa.

Imagen 5: Herencia de excepciones Java

Todas las excepciones tienen como clase base la clase Throwable, que está incluida en el paquete java.lang, y sus métodos son:

• Trowable( String mensaje ); Constructor. La cadena es opcional
• Throwable fillInStackTrace(); Llena la pila de traza de ejecución.
• String getLocalizedMessage(); Crea una descripción local de este objeto.
• String getMessage(); Devuelve la cadena de error del objeto.
• void printStackTrace( PrintStream_o_PrintWriter s ); Imprime este objeto y su traza en el flujo del parámetro s, o en la salida estándar (por defecto).
• String toString; Devuelve una breve descripción del objeto.

La superclase de todas las excepciones es la clase Throwable. Sólo las instancias de esta clase o alguna de sus subclases pueden ser utilizadas como excepciones. La clase Trowable tiene dos clases derivadas: Error y Exception.

La clase Exception sirve como superclase para crear excepciones de propósito específico (adaptadas a nuestras necesidades), por ejemplo, si estamos diseñando una clase que lee secuencialmente bytes en una cinta digital de datos, podemos crear la excepción: FinDeCinta que se produce cuando el dispositivo físico ha alcanzado el final de la cinta. Otro ejemplo podría ser la implementación de una clase de envío de datos a un satélite no geoestacionario, donde convendría incluir una excepción FueraDeCobertura que se produzca cuando el satélite se encuentre fuera del alcance de nuestra antena parabólica. Un último ejemplo: si escribimos un driver de impresora podemos crear una clase derivada de Exception para que nos avise de la situación excepcional FinDePapel .

La clase Error sirve de superclase para una serie de clases derivadas ya definidas que nos informan de situaciones anormales relacionadas con errores de muy difícil recuperación producidos en el sistema.

La clase Exception tiene un amplio número de clases derivadas proporcionadas por el SDK, por ejemplo existen excepciones predefinidas para el uso de ficheros, de SQL, etc. De todas estas subclases, RuntimeExeption tiene una característica propia: no es necesario realizar un tratamiento explícito de estas excepciones (de todas las demás clases derivadas de Exception si es necesario). Esto es debido a que, al igual que con las excepciones derivadas de Error, existen pocas posibilidades de recuperar situaciones.

5.3 PROPAGACIÓN DE EXCEPCIONES.

Las instrucciones que tenemos dentro de un bloque try a menudo contienen llamadas a métodos que a su vez pueden realizar llamadas a otros métodos y así sucesivamente. Cualquiera de los métodos llamados puede provocar una excepción y cualquiera de los métodos puede, o no, tratarla (con bloques catch). Ó
Una excepción no tratada en un bloque se propaga hacia el bloque llamante. Este mecanismo de propagación continúa mientras no se trate la excepción o se llegue al método de nivel superior. Si la excepción no se trata en el método de nivel superior, se imprime un mensaje de error por consola.

En el gráfico anterior se presenta el caso de un bloque try que contiene una llamada a un método Metodo_A que a su vez hace una llamada a Metodo_B, donde se produce una excepción. Como la excepción no es tratada en Metodo_B se propaga al bloque llamante (Metodo_A); a su vez la excepción no es tratada en Metodo_A, por lo que se propaga al bloque try, donde sí que es capturada por un catch.
En el caso de que un método capture y trate la excepción, el mecanismo de propagación se termina y la ejecución de los métodos llamados y el bloque try del método llamante continúan como si la excepción no se hubiera producido:

En muchas ocasiones, después de tratar la excepción a un nivel, resulta conveniente que también sea tratada a niveles superiores; por ejemplo, si estando leyendo de un fichero origen y escribiendo su contenido en un fichero destino nos encontramos con un error de lectura, además de tratar la excepción a ese nivel (cerrar los ficheros, etc.) sería deseable propagar la excepción al programa llamante para que informe al usuario y le permita hacer un nuevo intento si lo desea.
Para propagar de forma explícita una excepción se emplea la palabra reservada throw seguida del objeto excepción. Ejemplo:

try {
// codigo
Origen.CopiaFichero(Destino);
// codigo
}
catch (IOException e) {
System.out.println (“Error de lectura ¿Desea intentarlo de Nuevo?”);
..........
}

public void CopiaFichero (TipoFichero Destino) {
try {
// codigo
}
catch (IOException e) {
// cerrar ficheros, etc.
throw e;
}

En el ejemplo anterior, el método CopiaFichero, después de tratar la excepción, la propaga (throw) al método llamante, que a su vez hace otro tratamiento de la excepción.
ESTADO DE UNA EXCEPCIÓN

omo hemos visto, todas las excepciones derivan de la clase Throwable y tienen acceso a sus dos constructores y sus 7 métodos. El estado de las instancias de esta clase se compone de un String que sirve de mensaje indicando las características de la excepción y una pila de ejecución que contiene la relación de métodos que se encuentran en ejecución en el momento en el que se produce la excepción.
Los métodos más significativos de la clase Throwable son:

Para ilustrar la forma de uso de estos métodos, en la clase Excepcion2 modificamos el contenido de los bloques catch para imprimir la pila de ejecución:

16 catch (ArithmeticException e) {
17 System.out.println("Division por cero");
18 e.printStackTrace();
19 }
20
21 catch(IndexOutOfBoundsException e) {
22 System.out.println("Indice fuera del array");
23 e.printStackTrace();
24 }

A la nueva clase la hemos llamado Excepcion3. La instrucción donde se realiza la división se encuentra en la línea 12 del método main, mientras que la instrucción donde se asigna el valor a la posición concreta del array se encuentra en la línea 13 del método main. A continuación se muestra el resultado de una posible ejecución del programa:

Como se puede observar, cada instrucción e.printStackTrace() provoca la impresión de un breve mensaje acerca de la excepción, seguido de la pila de ejecución de los métodos del programa (en este caso sólo el método main) con indicación de la línea de cada método donde se ha producido la excepción.

5.4 Gestión de excepciones: manejo de excepciones, lanzamiento de excepciones.

Lanzamiento de excepciones: throw - throws
Muchas veces el programador dentro de un determinado método deberá comprobar si alguna condición de excepción se cumple, y si es así lanzarla. Para ello se utilizan las palabras reservadas throw y throws.
Por una parte la excepción se lanza mediante la sentencia throw:
if ( condicion_de_excepcion == true )
throw new miExcepcion();
Se puede observar que hemos creado un objeto de la clase miExcepcion, puesto que las excepciones son objetos y por tanto deberán ser instanciadas antes de ser lanzadas.
Aquellos métodos que pueden lanzar excepciones, deben cuáles son esas excepciones en su declaración. Para ello se utiliza la sentencia throws:
tipo_devuelto miMetodoLanzador() throws miExcep1, miExcep2 {
// Codigo capaz de lanzar excepciones miExcep1 y miExcep2
}
Se puede observar que cuando se pueden lanzar en el método más de una excepción se deben indicar en sus declaraciones separadas por comas.
d.) Ejemplo de gestión de excepciones
Ahora que ya sabemos cómo funciona este sistema, conviene ver al menos un pequeño ejemplo, que ilustre al lector en el uso de las excepciones:
// Creo una excepción personalizada

class MiExcepcion extends Exception {

MiExcepcion(){

super(); // constructor por defecto de Exception

}

MiExcepcion( String cadena ){

super( cadena ); // constructor param. de Exception

}

}

// Esta clase lanzará la excepción

class Lanzadora {

void lanzaSiNegativo( int param ) throws MiExcepcion {

if ( param < 0 )

throw new MiExcepcion( "Numero negativo" );

}

}

class Excepciones {

public static void main( String[] args ) {

// Para leer un fichero

Lanzadora lanza = new Lanzadora();

FileInputStream entrada = null;

int leo;

try {

entrada = new FileInputStream( "fich.txt" );

while ( ( leo = entrada.read() ) != -1 )

lanza.lanzaSiNegativo( leo );

entrada.close();

System.out.println( "Todo fue bien" );

} catch ( MiExcepcion e ){ // Personalizada

System.out.println( "Excepcion: " + e.getMessage() );

} catch ( IOException e ){ // Estándar

System.out.println( "Excepcion: " + e.getMessage() );

} finally {

if ( entrada != null )

try {

entrada.close(); // Siempre queda cerrado

} catch ( Exception e ) {

System.out.println( "Excepcion: " + e.getMessage() );

}

System.out.println( "Fichero cerrado." );

}

}

}

class Excepciones {

public static void main( String[] args ) {

// Para leer un fichero

FileInputStream entrada = null;

Lanzadora lanza = new Lanzadora();

int leo;

try {

entrada = new FileInputStream("fich.txt");

while ( ( leo = entrada.read() ) != -1 )

lanza.lanzaSiNegativo( leo );

System.out.println( "Todo fue bien" );

} catch ( MiExcepcion e ){ // Personalizada

System.out.println( "Excepcion: " + e.getMessage() );

} catch ( IOException e ){ // Estándar

System.out.println( "Excepcion: " + e.getMessage() );

} finally {

entrada.close(); // Así el fichero siempre queda cerrado

System.out.println( "Fichero cerrado" );

}

}

}

Este programa lee un fichero (fichero.txt), y lee su contenido en forma de números.
Si alguno de los números leídos es negativo, lanza una excepción MiExcepcion, Además gestiona la excepción IOException, que es una excepción de las que Java incluye y que se lanza si hay algún problema en una operación de entrada/salida.
Ambas excepciones son gestionadas, imprimiendo su contenido (cadena de error) por pantalla.
La salida de este programa, suponiendo un número negativo sería:
Excepcion: Numero negativo
Fichero cerrado
En el caso de que no hubiera ningún número negativo sería:
Todo fue bien
Fichero cerrado
En el caso de que se produjese un error de E/S, al leer el primer número, sería:
Excepcion: java.io.IOException
Fichero cerrado

5.5.CREACIÓN Y MANEJO DE EXCEPCIONES DEFINIDAS POR EL USUARIO.

Las excepciones predefinidas cubren las situaciones de error más habituales con las que nos podemos encontrar, relacionadas con el propio lenguaje y el hardware. Cuando se desarrollan aplicaciones existen otras situaciones de error de más ‘alto nivel’ relacionadas con la funcionalidad de nuestros programas.
Imaginemos una aplicación informática que controla la utilización de los remontes de una estación de esquí: los pases de acceso a los remontes son personales e intransferibles y dispondrán de un código de barras que los identifica. Cada vez que un usuario va a hacer uso de un remonte debe introducir su pase de acceso en una máquina de validación, que a cciona un torno y devuelve el pase. El sistema puede constar de un ordenador central al que le llegan telemáticamente los datos correspondientes a los códigos de barras de los pases que en cada momento se están introduciendo en cada máquina de validación d e cada remonte; si un código de barras está en regla, el ordenador envía una orden de liberar el torno para permitir al usuario acceder al remonte. El ordenador central habitualmente recibirá códigos correctos utilizados en momentos adecuados, sin embargo, en ciertas ocasiones nos encontraremos con situaciones anómalas:
1 Código de barras ilegible
2 Código de barras no válido (por ejemplo correspondiente a un pase caducado)
3 Código de barras utilizado en otro remonte en un periodo de tiempo demasiado breve
4 etc.
Ninguna de las situaciones anteriores se puede detectar utilizando excepciones predefinidas, puesto que su naturaleza está estrechamente relacionada con los detalles de la aplicación (no del lenguaje o el sistema informático), por lo que tendremos que recurrir al método tradicional de incluir condiciones (if, case, ...) de comprobación o bien hacer uso de excepciones definidas por nosotros mismos (excepciones no predefinidas).
Antes de nada tenemos que tener en cuenta que el mecanismo de excepciones es muy lento en ejecución comparado con la utilización de instrucciones condicionales. Aunque el mecanismo de excepciones es elegante, debemos utilizarlo con prudencia: únicamente en situaciones que realmente son excepcionales.
La primera situación anómala de nuestro ejemplo (código de barras ilegible) podría ser tratada como excepción o bien a través de alguna instrucción condicional, depende de la frecuencia con la que se nos presente esta situación. Si ocurre, por ejemplo, en aproximadamente un 0.5% de los casos, tendremos un claro candidato a ser tratado como excepción. Si ocurre, digamos en un 14% de los casos, deberíamos pensar en tratarlo con rapidez por medio de instrucciones condicionales. Para tratar la segunda situación anómala del ejemplo (código de barras no valido) deberíamos aplicar un razonamiento equivalente al que acabamos de realizar.
Nuestro tercer caso nos presenta la situación de que un mismo pase de pistas ha podido ser duplicado (intencionadamente o por error), puesto que resulta físicamente imposible hacer uso de un remonte en un instante y volver a utilizarlo en otro remonte lejano medio minuto después. Probablemente esta situación se presenta muy rara vez y resultaría muy adecuado tratarla como excepción propia.
Una vez razonada la utilidad de este tipo de excepciones, veremos la manera de definirlas en Java

Ejemplo:

//Demostracion del mecanismo de manejo de excepciones
//try...catch...finally

public class UsoDeExcepciones {
public static void main(String args[]){
try{
lanzaExcepcion();//llama al metodo lanzaExcepcion
}//fin de try
catch(Exception excepcion){ //excepcion lanzada por lanzaExcepcion
System.err.println("La excepcion se manejo en main ");
}//fin de catch
noLanzaExcepcion();
}//fin de main
//demuestra los bloques try...catch...finally

public static void lanzaExcepcion() throws Exception{
try{//lanza una excepcion y la atrapa de inmediato
System.out.println("Metodo lanzaExcepcion");
throw new Exception();//genera la excepcion
}//fin de try

catch (Exception excepcion){ //atrapa la excepcion lanzada en el bloque try
System.err.println("La excepcion se manejo en el metodo lanzaExcepcion ");
throw excepcion;//vuelve a lanzar para procesarla mas adelante
//no se llegaria al codigo que se coloque aqui, la excepcion se vuelve a lanzar en el bloque catch
}//fin catch
finally{//se ejecuta sin importar lo que ocurra en los bloques try..catch
System.err.println("Se ejecuto finally en lanzaExcepcion ");
}//din de finally
//no se llega al codigo que se coloque aqui, la excepcion se vuelve a lanzar en el bloque catch
}//fin del metodo lanzaException

//demuestra el uso de finally cuando no ocurre una excepcion
public static void noLanzaExcepcion(){
try{//el bloque try no lanza una excepcion
System.out.println("Metodo noLanzaExcepcion");
}//fin de try

catch(Exception excepcion){//no se ejecuta
System.err.println(excepcion);
}//fin de catch

finally{//se ejecuta sin importar lo que ocurra en los bloques try..catch
System.err.println("Se ejecuto Finally en noLanzaExcepcion");
}//fin de bloque finally

System.out.println("Fin del metodo noLanzaExcepcion");
}//fin del metodo noLanzaExcepcion

}//fin de la clase UsoDeExcepciones



more...
No comment yet.
Scooped by Cinthia Carrasco
Scoop.it!

Segunda Unidad

Segunda Unidad | Programación Orientada a Objetos ITSAVLerdo | Scoop.it

2.1 Declaración de clases: atributos, métodos, encapsulamiento.



La declaración de una clase define la estructura de la misma. Dicho de otra forma, la declaración de una clase informa de los elementos que la conforman. Posteriormente a ser declarada, una clase debe ser implementada convenientemente, es decir, se debe escribir el código correspondiente a los procedimientos y funciones que determinan el funcionamiento de esa clase.
Las clases se declaran en la sección TIPO del script pues las clases son, al fin y al cabo, tipos de datos.
La programación orientada a objetos se basa en la programación de clases; a diferencia de la programación estructurada, que está centrada en las funciones.
Una clase es un molde del que luego se pueden crear múltiples objetos, con similares características.
Una clase es una plantilla (molde), que define atributos (variables) y métodos (funciones)
La clase define los atributos y métodos comunes a los objetos de ese tipo, pero luego, cada objeto tendrá sus propios valores y compartirán las mismas funciones.
Debemos crear una clase antes de poder crear objetos (instancias) de esa clase. Al crear un objeto de una clase, se dice que se crea una instancia de la clase o un objeto propiamente dicho.

Tipos de atributos.
Objetivos:
a) Profundizar en el concepto de atributo de una clase e indicar los tipos de atributos en Java
b) Interpretar el código fuente de una aplicación Java donde aparecen distintos tipos de atributos
c) Construir una aplicación Java sencilla, convenientemente especificada, que emplee clases con diferentes tipos de atributos.

Los atributos, también llamados datos o variables miembro son porciones de información que un objeto posee o conoce de sí mismo. Una clase puede tener cualquier número de atributos o no Tener ninguno. Se declaran con un identificador y el tipo de dato correspondiente.

Modificador Visibilidad
public Pública (+)
protectec Protegida / en la herencia(#)
private Privada(-)
package De paquete (~)

Métodos.
Java como todo lenguaje de programación orientado a objetos utiliza los llamados métodos. A continuación veremos cómo se crea un método y como se utilizan.
Se podría decir que existen 2 grandes tipos de métodos, el primer tipo de método son métodos que realizan procesos, puedes realizar cualquier operación con ellos, sin embargo el propósito es manipular variables existentes. El segundo tipo de métodos son los que realizan un proceso o cálculo, y calculan una variable específica, un ejemplo podría ser un método para obtener el valor de una multiplicación.
Los métodos en java pueden tener parámetros, es decir, que un método puede utilizar variables predefinidas para ser utilizadas en sus procesos.

Encapsulamiento.
Como se puede observar de los diagramas, las variables del objeto se localizan en el centro o núcleo del objeto. Los métodos rodean y esconden el núcleo del objeto de otros objetos en el programa. Al empaquetamiento de las variables de un objeto con la protección de sus métodos se le llama encapsulamiento. Típicamente, el encapsulamiento es utilizado para esconder detalles de la puesta en práctica no importantes de otros objetos. Entonces, los detalles de la puesta en práctica pueden cambiar en cualquier tiempo sin afectar otras partes del programa.

El encapsulamiento de variables y métodos en un componente de software ordenado es, todavía, una simple idea poderosa que provee dos principales beneficios a los desarrolladores de software.

Modularidad.
esto es, el código fuente de un objeto puede ser escrito, así como darle mantenimiento, independientemente del código fuente de otros objetos. Así mismo, un objeto puede ser transferido alrededor del sistema sin alterar su estado y conducta.
Ocultamiento de la información, es decir, un objeto tiene una "interfaz publica" que otros objetos pueden utilizar para comunicarse con él. Pero el objeto puede mantener información y métodos privados que pueden ser cambiados en cualquier tiempo sin afectar a los otros objetos que dependan de ello.
Los objetos proveen el beneficio de la modularidad y el ocultamiento de la información. Las clases proveen el beneficio de la reutilización. Los programadores de software utilizan la misma clase, y por lo tanto el mismo código, una y otra vez para crear muchos objetos.
En las implantaciones orientadas a objetos se percibe un objeto como un paquete de datos y procedimientos que se pueden llevar a cabo con estos datos. Esto encapsula los datos y los procedimientos. La realidad es diferente: los atributos se relacionan al objeto o instancia y los métodos a la clase. ¿Por qué se hace así? Los atributos son variables comunes en cada objeto de una clase y cada uno de ellos puede tener un valor asociado, para cada variable, diferente al que tienen para esa misma variable los demás objetos. Los métodos, por su parte, pertenecen a la clase y no se almacenan en cada objeto, puesto que sería un desperdicio almacenar el mismo procedimiento varias veces y ello va contra el principio de reutilización de código.

2.2 Instanciación de una clase.


Podemos interpretar que una clase es el plano que describe como es un objeto de la clase, por tanto podemos entender que a partir de la clase podemos fabricar objetos. A ese objeto construido se le denomina instancia, y al proceso de construir un objeto se le llama instanciación.
Cuando se construye un objeto es necesario dar un valor inicial a sus atributos, es por ello que existe un método especial en cada clase, llamado constructor, que es ejecutado de forma automática cada vez que es instanciada una variable. Generalmente el constructor se llama igual que la clase y no devuelve ningún valor. Análogamente, destructor es un método perteneciente a una clase que es ejecutado de forma automática cuando un objeto es destruido. Java no soporta los destructores. Es posible que exista más de un constructor en una clase, diferenciados sólo en los parámetros que recibe, pero en la instanciación sólo será utilizado uno de los constructores.

Ejemplo:

clase base

package ejemplo_de_libro;

import java.util.Scanner;
public class Main {

public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
LibroCalificaciones miLibroCalificaciones = new LibroCalificaciones();
System.out.println("Escribe algo: ");
String nombreDelCurso = entrada.nextLine();
System.out.println();
miLibroCalificaciones.mostrarMensaje(nombreDelCurso);
}
}

clase derivada
package ejemplo_de_libro;

public class LibroCalificaciones {
public void mostrarMensaje(String nombredelsaludo)
{
System.out.printf("Bienvenido al libro de calificaciones para :\n%s\n", nombredelsaludo);
}
}

2.3 Referencia al objeto actual.

La utilización de THIS en lugar de hacer referencia explícitamente al objeto actual por su nombre (por ejemplo, thisform.command1.caption) hace que el código de programa pueda alternarse entre objetos, porque evita el nombre del objeto y encapsula automáticamente la clase primaria del objeto.

THIS permite hacer referencia a una propiedad o un objeto de una definición de clase. Los métodos de un bloque de definición de clase pueden utilizar THIS para especificar una propiedad o un objeto que existirá cuando se cree la clase.

Puesto que múltiples instancias de objetos comparten el mismo código de método, THIS siempre hace referencia a la instancia en la que está ejecutándose el código. Si hay múltiples instancias de un objeto, y se llama a uno de los métodos del objeto, THIS hace referencia al objeto correcto.

Cada objeto puede acceder a una referencia a si mismo mediante la palabra this. Cuando se hace una llamada a un método no static para un objeto especifico, el cuerpo del método utiliza en forma implícita la palabra this para hacer referencia a las variables de instancia y los demás métodos del objeto.

Ahora demostraremos el uso implícito y explicito de la referencia this para permitir al método main de la clase PruebaThis que muestre en pantalla los datos prívate de un objeto de la clase TiempoSimple. Hicimos esto para demostrar que, al compilador un archivo .java que contiene mas de una clase, el compilador produce un archivo de clase separado por la extensión .class para cada clase compilada.

// Ejemplo This.java

//Uso implicito y explicito de this para hacer referencia a los miembros de un objeto

public class PruebaThis
{
public static void main (String args[])
{
TiempoSimple tiempo=new TiempoSimple(15, 30, 19 );
System.out.println(tiempo.crearString());
}//fin de main
}//fin de la clase PruebaThis
//la clase TiempoSimple demuestra la referencia "this"
public class TiempoSimple
{
private int hora; //0-23
private int minuto; //0-59
private int segundo;//0-59
//si el constructor utiliza nombres de parametros identicos a
//los nombres de las variables de instancia, se reuiere la
//referencia "this" para diferenciar unos nombres de otros
public TiempoSimple (int hora,int minuto, int segundo)
{
this.hora=hora;//establece la hora del objeto "this"
this.minuto=minuto;//establece el minuto del objeto "this"
this.segundo=segundo;//establece el segundo del objeto "this"
}//fin del constructor de TiempoSimple
//usa la referencia "this" explicita e implicita para llamar StringUniversal
public String crearString()
{
return String.format("%24s:%s\n%24s:%s",
"this.aStringUniversal()",this.aStringUniversal(),
"aStringUniversal()",aStringUniversal());
}//fin del metodo crearString
//convierte a String en formato de hora universal (HH:MM:SS)
public String aStringUniversal()
{
//"this"no se requiere aqui para acceder a las variables de instancia,
//ya que el metodo no tiene variable locales con los mismos
//nombres que las variables de instancia
return String.format("%02d:%02d:%02d",
this.hora, this.minuto, this.segundo);
}//fin del metodo sStringUniversal
}//fin de la clase TiempoSimple

2.4 Métodos : Declaración , Mensajes , Paso de parámetros, Retorno de valores.



Los métodos o funciones miembro se definen dentro de la clase a la que pertenecen y constituyen la interfaz o forma de acceder a la estructura interna de los objetos es decir a los datos privados.

Los métodos definen cual son las operaciones que se pueden realizar con los atributos de los objetos de la clase. La ejecución de un programa orientado a objetos consiste, en recibir, interpretar y responder unos objetos a los mensajes que envían otros objetos. En P.O.O. un mensaje está asociado siempre con un método, de manera que cuando un objeto recibe un mensaje la respuesta a ese mensaje es ejecutar el método asociado

Modo de acceso:
Específica el tipo de acceso permitido indicando que usuarios de la clase podrán acceder a ese método, los métodos son la única forma de acceso a los atributos privados. Por defecto los métodos tienen protección paquete, es decir son accesibles desde cualquier clase que pertenezca al mismo paquete. Todas las clases de un mismo fichero .java pertenecen a un mismo paquete.
Public: Accesible desde cualquier otra clase.
Package: Accesible sólo desde el mismo paquete.
Protected: Se comporta como un método público para los métodos del mismo paquete o de las subclases y para el resto como un método privado.
Prívate: Sólo accesible a través de métodos de la propia clase.

Retorno de valores:
Un método puede devolver un valor a quien lo llama o no devolver nada. El valor devuelto por un método puede ser de un tipo primitivo de datos o una referencia, pero nunca puede devolver más de un valor. El valor de retorno nunca puede ser un objeto de una superclase, sí de la misma clase o de una subclase. Si el método no devuelve nada el tipo devuelto por el método es el tipo void.

Paso de parámetros a una función o método.

Los parámetros de una función son variables locales que se inicializan en el momento de la llamada al método. Fuera de la función no se conocen y no pueden ser accedidas. Se crean al entrar en la función y se destruyen al salir de ella.
El paso de parámetros o argumentos a las funciones se puede hacer de dos formas. Paso por valor , paso por referencia.

2.5 Constructores y Destructores: Declaración, Uso y sus Aplicaciones.

Para crear un objeto se necesita reservar suficiente espacio en memoria e inicializar los valores de los campos que representan el estado del objeto. Este trabajo es realizado por un tipo especial de método denominado constructor.

Constructor
Un método constructor de una clase es un método especial que: tiene el mismo nombre que la clase y no tiene tipo de retorno. La sintaxis para la declaración de un método constructor es:

[atributos] [modificadores] ( [parámetros] ) [inicializador]
{
// Cuerpo del constructor.
}
Donde: atributos (opcional) es información declarativa adicional, modificadores (opcional) se restringen a extern y a los modificadores de acceso, identificador es el nombre del método constructor (igual al nombre de la clase), parámetros (opcional) es la lista de parámetros pasados al constructor, inicializador (opcional). Con el inicializador, el constructor invoca previamente a otro constructor.
El inicializador puede ser uno de los siguientes: base([listaDeParámetros]) this([listaDeParámetros])
Cuerpo del constructor es el bloque de programa que contiene las instrucciones para inicializar la instancia de clase (objeto).
Destructor
La sintaxis para declarar un destructor es:
[Atributos] ~ ( )
{
// Cuerpo del destructor.
}
Una clase solamente puede tener un destructor. Los destructores no pueden heredarse o sobrecargarse, los destructores no pueden invocarse, sino que son invocados automáticamente, un destructor no acepta modificadores ni parámetros, por ejemplo, la siguiente es una declaración de un destructor para la clase Figura:
~ Figura()
{
// Instrucciones para limpiar.
}

La destrucción por defecto: Recogida de basura

El intérprete de Java posee un sistema de recogida de basura, que por lo general permite que no nos preocupemos de liberar la memoria asignada explícitamente.
El recolector de basura será el encargado de liberar una zona de memoria dinámica que había sido reservada mediante el operador new, cuando el objeto ya no va a ser utilizado más durante el programa (por ejemplo, sale del ámbito de utilización, o no es referenciado nuevamente).
El sistema de recogida de basura se ejecuta periódicamente, buscando objetos que ya no estén referenciados.

La destrucción personalizada: finalize

A veces una clase mantiene un recurso que no es de Java como un descriptor de archivo o un tipo de letra del sistema de ventanas. En este caso sería acertado el utilizar la finalización explícita, para asegurar que dicho recurso se libera. Esto se hace mediante la destrucción personalizada, un sistema similar a los destructores de C++.
Para especificar una destrucción personalizada se añade un método a la clase con el nombre finalize.

2.6 Sobrecarga de métodos.

Un método sobrecargado se utiliza para reutilizar el nombre de un método pero con diferentes argumentos (opcionalmente un tipo diferente de retorno). Las reglas para sobrecargar un método son las siguientes:

Los métodos sobrecargados deben de cambiar la lista de argumentos.
Pueden cambiar el tipo de retorno.
Pueden cambiar el modificador de acceso.
Pueden declarar nuevas o más amplias excepciones.
Un método puede ser sobrecargado en la misma clase o en una subclase.

Veamos un método que se desea sobrecargar:

public void cambiarTamano(int tamano, String nombre, float patron){ }

Los siguientes métodos son sobrecargas legales del método cambiarTamano():

public void cambiarTamano(int tamano, String nombre){}
public int cambiarTamano(int tamano, float patron){}
public void cambiarTamano(float patron, String nombre) throws IOException{}

Cómo invocar un método sobrecargado:

Lo que define qué método es el que se va a llamar son los argumentos que se envían al mismo durante la llamada. Si se invoca a un método con un String como argumento, se ejecutará el método que tome un String como argumento, si se manda a llamar al mismo método pero con un float como argumento, se ejecutará el método que tome un float como argumento y así sucesivamente. Si se invoca a un método con un argumento que no es definido en ninguna de las versiones sobrecargadas entonces el compilador arrojará un mensaje de error.
Reglas de la sobrecarga y sobreescritura de métodos:
Ahora que hemos visto ambas formas de reescribir métodos, revisemos las reglas y diferencias entre ambos tipos de reescritura:

Argumentos: En un método sobrecargado los argumentos deben de cambiar mientras que en un método sobreescrito NO deben cambiar.
El tipo de retorno: En un método sobrecargado el tipo de retorno puede cambiar, en un método sobreescrito NO puede cambiar, excepto por subtipos del tipo declarado originalmente.
Excepciones: En un método sobrecargado las excepciones pueden cambiar, en un método sobreescrito pueden reducirse o eliminarse pero NO deben de arrojarse excepciones nuevas o más amplias.
Acceso: En un método sobrecargado puede cambiar, en un método sobreescrito el acceso NO debe de hacerse más restrictivo (puede ser menos restrictivo).
Al invocar: En un método sobrecargado los argumentos son los que determinan qué método es el que se invocará, en un método sobreescrito el tipo de objeto determina qué método es elegido.

Ejemplo :

clase base

package sobrekarga;

public class Main {

public static void main(String[] args) {
// TODO code application logic here
articulo objarticulo=new articulo();
objarticulo.fijarprecio("70");
objarticulo.mostrarprecio();

edad objedad= new edad();
objedad.poneredad();
objedad.mostraredad();
}
}

Clase articulo

package sobrekarga;

public class articulo {
private double precio;

public void fijarprecio(){
precio=5.50;

}
public void fijarprecio(String precio){

System.out.println("No es un valor");
}
public void fijaprecio (double precio){
this.precio=precio;
}
public void mostrarprecio(){
System.out.printf("precio es %.2f",precio);
System.out.println();
}
}

Clase edad

package sobrekarga;

public class edad {
private int edad;

public void poneredad(){
edad= 22;
}
public void poneredad(String edad){
System.out.println("no es una edad");
}
public void poneredad(int edad){
this.edad= edad;
}
public void mostraredad(){
System.out.printf("la edad es : %d ",edad);
System.out.println();
}
}

2.7 Sobrecarga de operadores: Concepto y utilidad, operadores Unarios y Binarios.

La sobrecarga de operadores es la capacidad para transformar los operadores de un lenguaje como por ejemplo el +, -, etc, cuando se dice transformar se refiere a que los operandos que entran en juego no tienen que ser los que admite el lenguaje por defecto. Mediante esta técnica podemos sumar dos objetos creados por nosotros o un objeto y un entero, en vez de limitarnos a sumar números enteros o reales, por ejemplo.
La sobrecarga de operadores ya era posible en c++ y en otros lenguajes, pero sorprendentemente java no lo incorpora, así que podemos decir que esta característica es una ventaja de c# respecto a java, aunque mucha gente, esta posibilidad, no lo considera una ventaja porque complica el código.

A la hora de hablar de operadores vamos a distinguir entre dos tipos, los unarios y los binarios. Los unarios son aquellos que solo requieren un operando, por ejemplo a++, en este caso el operando es 'a' y el operador '++'. Los operadores binarios son aquellos que necesitan dos operadores, por ejemplo a+c , ahora el operador es '+' y los operandos 'a' y 'c'. Es importante esta distinción ya que la programación se hará de forma diferente.

Los operadores que podemos sobrecargar son los unarios, +, -, !, ~, ++, --; y los binarios +, -, *, /, %, &, |, ^, <<, >>. Es importante decir que los operadores de comparación, ==, !=, <, >, <=, >=, se pueden sobrecargar pero con la condición que siempre se sobrecargue el complementario, es decir, si sobrecargamos el == debemos sobrecargar el !=

Operadores Unarios

En esta sección se verá cómo sobrecargar los operadores unarios, es decir aquellos que toman un solo operando, como por ejemplo a++. El prototipo de los métodos que van a sobrecargar operadores unarios será:
public static Operando operator++(Operando a)
Como antes sustituyendo el ++ por cualquier operador unario. El ejemplo dentro de nuestra clase de números complejos sería:

public static ComplexNum operator++(ComplexNum a)
{

float auximg = a.Img;
float auxreal = a.Real;

return new ComplexNum(++auxreal, ++auximg);
}

Operadores binarios

Para empezar vamos a sobrecargar el operador suma('+') para que al sumar dos objetos de la clase ComplexNum, es decir dos números complejos obtengamos un número complejo que será la suma de ambas partes. Cabe destacar que los prototipos para sobrecargar operadores serán:
public static Operando operator+(Operando a, Operando b)
Este es el prototipo para el operador +, el resto de operadores binarios van a seguir el mismo patrón. Por tanto el código del método de sobrecarga será el siguiente:

public static ComplexNum operator+(ComplexNum a, ComplexNum b)
{
return new ComplexNum(a.Real + b.Real, a.Img + b.Img);
}

Este método sobrecarga el operador suma para que podamos sumar dos números complejos. Un dato a tener en cuenta es que los métodos que sobrecargan operadores deben ser static. Como se ve en el código los operandos son 'a' y 'b', que se reciben como parámetro y el resultado de la operación es otro número complejo que es el que retorna el método. Por tanto se limita a crear un nuevo número complejo con ambas partes operadas. De la misma forma podemos crear la sobrecarga del operador resta('-') para que lleve a cabo la misma función:

public static ComplexNum operator-(ComplexNum a, ComplexNum b)
{
return new ComplexNum(a.Real - b.Real, a.Img - b.Img);

more...
No comment yet.
Scooped by Cinthia Carrasco
Scoop.it!

Cuarta Unidad

Cuarta Unidad | Programación Orientada a Objetos ITSAVLerdo | Scoop.it

4.1 Definición.




El polimorfismo es un concepto de la programación orientada a objetos que nos permite programar en forma general, en lugar de hacerlo en forma específica. En general nos sirve para programar objetos con características comunes y que todos estos compartan la misma superclase en una jerarquía de clases, como si todas fueran objetos de la superclase. Esto nos simplifica la programación.

Recuerde el ejemplo del ecosistema, en donde todos los objetos de las distintas especies heredaban de una superclase llamada Animal, que brindaba la información general de cualquier animal, independiente de su especie. Sin embargo, cada especie hace un uso particular de cada uno de los métodos u operaciones de la clase Animal. El método comer() no se ejecutará de la misma manera en un León() o en un Pavo(). Lo mismo ocurre para métodos moverse() en objetos de tipo Tiburón() o Gallina(), aunque todas las especies realicen estos métodos. A la sobrescritura o implementación específica de métodos es la clave del polimorfismo.

Para poner en práctica se hará un ejemplo bastante sencillo. Se hará una librería de clases que represente figuras tridimensionales y bidimensionales, y su respectiva jerarquía de clases. Las clases deben ser capaces de tener funcionamiento bastante básico, como obtener áreas, volúmenes y perímetros de la figura correspondiente.

La representación de la jerarquía sería como ésta:


La superclase de dicha jerarquía podría ser muy parecida a ésta:

public abstract class figura {

protected String nombre;
protected int color;
protected int grosorBorde;

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

public int getColor(){
return this.color;
}

public void setColor(int c){
this.color=c;
}

public int getGrosorBorde(){
return this.grosorBorde;
}

public void setGrosorBorde(int g){
this.grosorBorde=g;
}

public abstract void dibujar();
}

Las siguientes clases en el nivel de la jerarquía podrían quedar muy parecidas a éstas:

public abstract class figura2D extends figura {

public abstract int calcularArea();

public abstract int calcularPerimetro();
}

public abstract class figura3D extends figura {

public abstract int calcularVolumen();
}



4.2 Clases abstractas: definición, métodos abstractos, implementación de clases abstractas, modelado de clases abstractas.

Las clases abstractas en Java

Una de las características más útiles de cualquier lenguaje orientado a objetos es la posibilidad de declarar clases que definen como se utiliza solamente, sin tener que implementar método. Esto en Java se hace mediante interfaces y con clases abstractas.

Una clase abstracta es una clase de la que no se puede crear objetos. La utilidad de estas clases estriba en que otras clases hereden de ésta, por lo que con ello conseguiremos reutilizar código. Para declarar una clase como abstracta utilizamos la palabra clave abstract.

En método abstract no pude ser static, ya que estos no pueden ser redifinidos por las subclases.

Clases abstractas

Una clase que declara la existencia de métodos pero no la implementación de dichos métodos (o sea, las llaves { } y las sentencias entre ellas), se considera una clase abstracta.

Una clase abstracta puede contener métodos no-abstractos pero al menos uno de los métodos debe ser declarado abstracto.

Para declarar una clase o un metodo como abstractos, se utiliza la palabra
reservada abstract.

abstract class ejemplo

{
abstract void miMetodo(int var1, int var2);
String miOtroMetodo( ){ ... }
}

Una clase abstracta no se puede instanciar pero si se puede heredar y las clases hijas serán las encargadas de agregar la funcionalidad a los métodos abstractos. Si no lo hacen así, las clases hijas deben ser también abstractas.

4.3 Interfaces: definición, implementación de interfaces, herencia de interfaces.
INTERFACES

Las interfaces Java son expresiones puras de diseño. Se trata de auténticas conceptualizaciones no implementadas que sirven de guía para definir un determinado concepto (clase) y lo que debe hacer, pero sin desarrollar un mecanismo de solución.
Se trata de declarar métodos abstractos y constantes que posteriormente puedan ser implementados de diferentes maneras según las necesidades de un programa.
Por ejemplo una misma interfaz podría ser implementada en una versión de prueba de manera poco óptima, y ser acelerada convenientemente en la versión definitiva tras conocer más a fondo el problema.

Declaración

Para declarar una interfaz se utiliza la sentencia interface, de la misma manera que se usa la sentencia class:

interface MiInterfaz {

int CONSTANTE = 100;

int metodoAbstracto( int parametro );

}

Se observa en la declaración que las variables adoptan la declaración en mayúsculas, pues en realidad actuarán como constantes final. En ningún caso estas variables actuarán como variables de instancia.
Por su parte, los métodos tras su declaración presentan un punto y coma, en lugar de su cuerpo entre llaves. Son métodos abstractos, por tanto, métodos sin implementación

Implementación de una interfaz

Como ya se ha visto, las interfaces carecen de funcionalidad por no estar implementados sus métodos, por lo que se necesita algún mecanismo para dar cuerpo a sus métodos.
La palabra reservada implements utilizada en la declaración de una clase indica que la clase implementa la interfaz, es decir, que asume las constantes de la interfaz, y codifica sus métodos:

class ImplementaInterfaz implements MiInterfaz{

int multiplicando=CONSTANTE;

int metodoAbstracto( int parametro ){

return ( parametro * multiplicando );

}

}

En este ejemplo se observa que han de codificarse todos los métodos que determina la interfaz (metodoAbstracto()), y la validez de las constantes (CONSTANTE) que define la interfaz durante toda la declaración de la clase.
Una interfaz no puede implementar otra interfaz, aunque sí extenderla (extends) ampliándola.

Herencia múltiple

Java es un lenguaje que incorpora herencia simple de implementación pero que puede aportar herencia múltiple de interfaz. Esto posibilita la herencia múltiple en el diseño de los programas Java.
Una interfaz puede heredar de más de una interfaz antecesora.
interface InterfazMultiple extends Interfaz1,Interfaz2{ }
Una clase no puede tener más que una clase antecesora, pero puede implementar más de una interfaz:

class MiClase extends SuPadre implements Interfaz1,Interfaz2{ }

El ejemplo típico de herencia múltiple es el que se presenta con la herencia en diamante:

Para poder llevar a cabo un esquema como el anterior en Java es necesario que las clases A, B y C de la figura sean interfaces, y que la clase D sea una clase (que recibe la herencia múltiple):

interface A{ }
interface B extends A{ }
interface C extends A{ }
class D implements B,C{ }

Colisiones en la herencia múltiple

En una herencia múltiple, los identificadores de algunos métodos o atributos pueden coincidir en la clase que hereda, si dos de las interfaces padres tienen algún método o atributo que coincida en nombre. A esto se le llama colisión.
Esto se dará cuando las clases padre (en el ejemplo anterior B y C) tienen un atributo o método que se llame igual. Java resuelve el problema estableciendo una serie de reglas.
Para la colisión de nombres de atributos, se obliga a especificar a qué interfaz base pertenecen al utilizarlos.
Para la colisión de nombres en métodos:

• Si tienen el mismo nombre y diferentes parámetros: se produce sobrecarga de métodos permitiendo que existan varias maneras de llamar al mismo.
• Si sólo cambia el valor devuelto: se da un error de compilación, indicando que no se pueden implementar los dos.
• Si coinciden en su declaración: se elimina uno de los dos, con lo que sólo queda uno.

Envolturas de los tipos simples

Los tipos de datos de Java no forman parte de la jerarquía de objetos. Sin embargo a veces es necesario crear una representación como objeto de alguno de los tipos de datos simples de Java.
La API de Java contiene un conjunto de interfaces especiales para modificar el comportamiento de los tipos de datos simple. A estas interfaces se las conoce como

envolturas de tipo simple.

Todas ellas son hijas de la clase abstracta Number y son:

• Double: Da soporte al tipo double.
• Float: Da soporte al tipo float.
• Integer: Da soporte a los tipos int, short y byte.
• Long: Da soporte al tipo long.
• Character: Envoltura del tipo char.
• Boolean: Envoltorio al tipo boolean.

4.4 Variables polimórficas (plantillas): definición, uso y aplicaciones.

En Java, las variables que contienen objetos son variables polimórficas. El término «polimórfico» (literalmente: muchas formas) se refiere al hecho de que una misma variable puede contener objetos de diferentes tipos (del tipo declarado o de cualquier subtipo del tipo declarado). El polimorfismo aparece en los lenguajes orientados a objetos en numerosos contextos, las variables polimórficas constituyen justamente un primer ejemplo.

Observemos la manera en que el uso de una variable polimórfica nos ayuda a simplificar nuestro método listar. El cuerpo de este método es:

for (Elemento elemento : elementos)
elemento.imprimir();
En este método recorremos la lista de elementos (contenida en un ArrayList mediante la variable elementos), tomamos cada elemento de la lista y luego invocamos su método imprimir.El uso de herencia en este ejemplo ha eliminado la necesidad de escribir dos ciclos en el método listar. La herencia evita la duplicación de código no sólo en las clases servidoras sino también en las clases clientes de aquellas.

public class CD
{
private String title;
private String artist;
private String comment;
CD(String theTitle, String theArtist)
{
title = theTitle;
artist = theArtist;
comment = " ";
}
void setComment(String newComment)
{ ... }
String getComment()
{ ... }
void print()
{ ... }
...
}

public class DVD
{
private String title;
private String director;
private String comment;
DVD(String theTitle, String theDirector)
{
title = theTitle;
director = theDirector;
comment = " ";
}
void setComment(String newComment)
{ ... }
String getComment()
{ ... }
void print()
{ ... }
...
}

class Database {
private ArrayList cds;
private ArrayList dvds;
...
public void list()
{
for(CD cd : cds) {
cd.print();
System.out.println(); }
for(DVD dvd : dvds) {
dvd.print();
System.out.println(); }
}
}

4.5 Reutilización de código.

Lo primero que se les viene a la cabeza a los estudiantes (y a muchos profesionales) cuando se les menciona la reutilización del código es el famoso copiar y pegar al que se han acostumbrado en la programación estructurada, y de echo muchos lo hacen en poo, lo cual es una de las practicas que más encarece el desarrollo de software. Como todo en Java, el problema se resuelve con las clases. Para reutilizar el código creamos nuevas clases pero, en lugar de partir de cero, partimos de clases, relacionadas con nuestra clase, que han sido ya creadas y depuradas. El truco está en usar las clases sin ensuciar el código existente.

Una forma de hacer esto es crear objetos de nuestras clases existentes dentro de la nueva clase. Esto se conoce como composición porque la nueva clase está compuesta de objetos de clases existentes. Estamos reutilizando la funcionalidad del código, y no la forma.

Otra forma es crear una nueva clase como un tipo de una clase ya existente. Tomamos la forma de la clase existente y añadimos código a la nueva, sin modificar la clase existente. Esta forma de crear nuevos objetos se llamada herencia, y lo que hacemos es extender la clase en la que nos basamos para crear la nueva.

Composición:
Hasta ahora hemos usado la composición de cierta manera, ej. cuando hacemos una interfaz gráfica de usuario, nuestra clase de interfaz gráfica esta compuesta por un frame, unos panel, botones, etc. todos estos objetos componen el objeto de interfaz gráfica. Es decir que la composición consiste en poner manejadores de objetos dentro de nuestra clase, estos manejadores de objetos no serán otra cosa que instancias de las clases en las que nos estamos basando para crear la nueva clase.

Recordemos que la forma para determinar cuando usar composición es cuando podemos decir que nuestra nueva clase “tiene un” elemento de otro tipo de objetos, por ejemplo un cronómetro tiene: horas, minutos y segundos, es decir que una clase Cronometro esta compuesta por otras clases llamadas: Horas, Minutos y Segundos.

Veamos como seria esta clase:

public class Cronometro {
Horas h;
Minutos m;
Segundos s;

String cadena;
int seg,min,hor;

public Cronometro() {
seg=0;
min=0;
hor=0;
h = new Horas();
m = new Minutos();
s = new Segundos();
cadena = new String("0 : 0 : 0");
}

public String avanzar(){
seg = s.forward();
if(seg==0){
min=m.forward();
if(min==0){
hor=h.forward();
}
}
cadena = hor + " : " + min + " : " + seg;
return cadena;
}

public String reset(){
seg = s.reset();
min = m.reset();
hor = h.reset();
cadena = hor + " : " + min + " : " + seg;
return cadena;
}
}

more...
No comment yet.
Scooped by Cinthia Carrasco
Scoop.it!

Sexta Unidad

Sexta Unidad | Programación Orientada a Objetos ITSAVLerdo | Scoop.it

6.1Flujos. Definición



Un Flujo de E/S representa una fuente de entrada y un destino de salida. Un flujo puede representar muchos tipos diferentes de fuentes y destinos, incluyendo archivos de disco, dispositivos, otros programas y arreglos de memoria.
Los flujos soportan muchos tipos diferentes de datos, incluyendo bytes simples, tipos primitivos de datos, caracteres localizados, y objetos. Algunos flujos simplementa pasan datos, otros manipulan y transforman datos en formas útiles.
No importa cómo trabajan internamente; todos los flujos presentan el mismo modelo simple a los programas que los usan: un flujo es una secuencia de datos. Un programa usa un flujo de entrada para leer datos desde una fuente, o artículo a la vez:

Leyendo información hacia un programa.
Un programa usa un flujo de salida para escribir datos a su destino, o artículo a la vez:

Escribiendo información desde un programa.

La fuente y el destino de datos retratado arriba puede ser cualquier cosa que mantenga, genere o consuma datos. Obviamente esto incluye archivos en disco, pero una fuente o destino puede también ser otro programa, un dispositivo periférico, un socket de red, o un arreglo.

6.2 Clasificación: Archivos de texto y binarios.



Definición Archivos Texto Binarios
Definición de archivos de texto y binarios
Los archivos de texto plano son aquellos que están compuestos únicamente por texto sin formato, solo caracteres. estos caracteres se pueden codificar de distintos modos dependiendo de la lengua usada. Se les conoce también como archivos de texto llano o texto simple por carecer de información destinada a generar formatos y tipos de letra.
Un archivo binario es una archivo informático que contiene información de cualquier tipo, codificada en forma binaria para el propósito de almacenamiento y procesamiento de ordenadores.
Muchos formatos binarios contienen partes que pueden ser interpretados como texto. Un archivo binario que solo contiene información de tipo textual sin información sobre el formato del mismo, se dice que es un archivo de texto plano. Habitualmente se contraponen los términos archivo binario y archivo de texto de forma que los primeros no contienen solamente texto.

6.3 Operaciones básicas y tipos de acceso.



Normalmente, cuando se codifica un programa, se hace con la intención de que ese programa pueda interactuar con los usuarios del mismo, es decir, que el usuario pueda pedirle que realice cosas y pueda suministrarle datos con los que se quiere que haga algo. Una vez introducidos los datos y las órdenes, se espera que el programa manipule de alguna forma esos datos para proporcionarnos una respuesta a lo solicitado.
Además, en muchas ocasiones interesa que el programa guarde los datos que se le han introducido, de forma que si el programa termina los datos no se pierdan y puedan ser recuperados en una sesión posterior. La forma más normal de hacer esto es mediante la utilización de ficheros que se guardarán en un dispositivo de memoria no volátil (normalmente un disco).
A todas estas operaciones, que constituyen un flujo de información del programa con el exterior, se les conoce como Entrada/Salida (E/S).
Existen dos tipos de E/S; la E/S estándar que se realiza con el terminal del usuario y la E/S a través de fichero, en la que se trabaja con ficheros de disco.
Todas las operaciones de E/S en Java vienen proporcionadas por el paquete estándar de la API de Java denominado java.io que incorpora interfaces, clases y excepciones para acceder a todo tipo de ficheros. En este tutorial sólo se van a dar algunas pinceladas de la potencia de este paquete.
B. Entrada/Salida estándar
Aquí sólo trataremos la entrada/salida que se comunica con el usuario a través de la pantalla o de la ventana del terminal.
Si creamos una applet no se utilizarán normalmente estas funciones, ya que su resultado se mostrará en la ventana del terminal y no en la ventana de la applet. La ventana de la applet es una ventana gráfica y para poder realizar una entrada o salida a través de ella será necesario utilizar el AWT.
El acceso a la entrada y salida estándar es controlado por tres objetos que se crean automáticamente al iniciar la aplicación: System.in, System.out y System.err
a.) System.in
Este objeto implementa la entrada estándar (normalmente el teclado). Los métodos que nos proporciona para controlar la entrada son:
• read(): Devuelve el carácter que se ha introducido por el teclado leyéndolo del buffer de entrada y lo elimina del buffer para que en la siguiente lectura sea leído el siguiente carácter. Si no se ha introducido ningún carácter por el teclado devuelve el valor -1.
• skip(n): Ignora los n caracteres siguientes de la entrada.
b.) System.out
Este objeto implementa la salida estándar. Los métodos que nos proporciona para controlar la salida son:
• print(a): Imprime a en la salida, donde a puede ser cualquier tipo básico Java ya que Java hace su conversión automática a cadena.
• println(a): Es idéntico a print(a) salvo que con println() se imprime un salto de línea al final de la impresión de a.
c.) System.err
Este objeto implementa la salida en caso de error. Normalmente esta salida es la pantalla o la ventana del terminal como con System.out, pero puede ser interesante redirigirlo, por ejemplo hacia un fichero, para diferenciar claramente ambos tipos de salidas.
Las funciones que ofrece este objeto son idénticas a las proporcionadas por System.out.
d.) Ejemplo
A continuación vemos un ejemplo del uso de estas funciones que acepta texto hasta que se pulsa el retorno de carro e informa del número de caracteres introducidos.
import java.io.*;

class CuentaCaracteres {

public static void main(String args[]) throws IOException {

int contador=0;

while(System.in.read()!='\n')

contador++;

System.out.println(); // Retorno de carro "gratuito"

System.out.println("Tecleados "+contador+" caracteres.");

}

}

C. Entrada/Salida por fichero
a.) Tipos de ficheros
En Java es posible utilizar dos tipos de ficheros (de texto o binarios) y dos tipos de acceso a los ficheros (secuencial o aleatorio).
Los ficheros de texto están compuestos de caracteres legibles, mientras que los binarios pueden almacenar cualquier tipo de datos (int, float, boolean,...).
Una lectura secuencial implica tener que acceder a un elemento antes de acceder al siguiente, es decir, de una manera lineal (sin saltos). Sin embargo los ficheros de acceso aleatorio permiten acceder a sus datos de una forma aleatoria, esto es indicando una determinada posición desde la que leer/escribir.
b.) Clases a estudiar
En el paquete java.io existen varias clases de las cuales podemos crear instancias de clases para tratar todo tipo de ficheros.
En este tutorial sólo vamos a trata las tres principales:
• FileOutputStream: Fichero de salida de texto. Representa ficheros de texto para escritura a los que se accede de forma secuencial.
• FileInputStream: Fichero de entrada de texto. Representa ficheros de texto de sólo lectura a los que se accede de forma secuencial.
• RandomAccessFile: Fichero de entrada o salida binario con acceso aleatorio. Es la base para crear los objetos de tipo fichero de acceso aleatorio. Estos ficheros permiten multitud de operaciones; saltar hacia delante y hacia atrás para leer la información que necesitemos en cada momento, e incluso leer o escribir partes del fichero sin necesidad de cerrarlo y volverlo a abrir en un modo distinto.
c.) Generalidades
Para tratar con un fichero siempre hay que actuar de la misma manera:
1. Se abre el fichero.
Para ello hay que crear un objeto de la clase correspondiente al tipo de fichero que vamos a manejar, y el tipo de acceso que vamos a utilizar:
TipoDeFichero obj = new TipoDeFichero( ruta );
Donde ruta es la ruta de disco en que se encuentra el fichero o un descriptor de fichero válido.
Este formato es válido, excepto para los objetos de la clase RandomAccessFile (acceso aleatorio), para los que se ha de instanciar de la siguiente forma:
RandomAccessFile obj = new RandomAccessFile( ruta, modo );
Donde modo es una cadena de texto que indica el modo en que se desea abrir el fichero; "r" para sólo lectura o "rw" para lectura y escritura.
2. Se utiliza el fichero.
Para ello cada clase presenta diferentes métodos de acceso para escribir o leer en el fichero.
3. Gestión de excepciones (opcional, pero recomendada)
Se puede observar que todos los métodos que utilicen clases de este paquete deben tener en su definición una cláusula throws IOException. Los métodos de estas clases pueden lanzar excepciones de esta clase (o sus hijas) en el transcurso de su ejecución, y dichas excepciones deben de ser capturadas y debidamente gestionadas para evitar problemas.
4. Se cierra el fichero y se destruye el objeto.
Para cerrar un fichero lo que hay que hacer es destruir el objeto. Esto se puede realizar de dos formas, dejando que sea el recolector de basura de Java el que lo destruya cuando no lo necesite (no se recomienda) o destruyendo el objeto explícitamente mediante el uso del procedimiento close() del objeto:
obj.close()
d.) La clase FileOutputStream
Mediante los objetos de esta clase escribimos en ficheros de texto de forma secuencial.
Presenta el método write() para la escritura en el fichero. Presenta varios formatos:
• int write( int c ): Escribe el carácter en el fichero.
• int write( byte a[] ): Escribe el contenido del vector en el fichero.
• int write( byte a[], int off, int len ): Escribe len caracteres del vector a en el fichero, comenzando desde la posición off.
El siguiente ejemplo crea el fichero de texto "/carta.txt" a partir de un texto que se le introduce por teclado:
import java.io.*;

class CreaCarta {

public static void main(String args[]) throws IOException{

int c;

FileOutputStream f=new FileOutputStream("/carta.txt");

while( ( c=System.in.read() ) != -1 )

f.write( (char)c );

f.close();

}

}

e.) La clase FileInputStream
Mediante los objetos de esta clase leemos de ficheros de texto de forma secuencial.
Presenta el método read() para la lectura del fichero. Este método se puede invocar de varias formas.
• int read(): Devuelve el siguiente carácter del fichero.
• int read( byte a[] ): Llena el vector a con los caracteres leídos del fichero. Devuelve la longitud del vector que se ha llenado si se realizó con éxito o –1 si no había suficientes caracteres en el fichero para llenar el vector.
• int read( byte a[], int off, int len ): Lee len caracteres del fichero, insertándolos en el vector a.
Todos ellos devuelven -1 si se ha llegado al final del fichero (momento de cerrarle).
El siguiente ejemplo muestra el fichero de texto "/carta.txt" en pantalla:
import java.io.*;

class MuestraCarta {

public static void main(String args[]) throws IOException {

int c;

FileInputStream f=new FileInputStream("/carta.txt");

while( ( c=f.read() ) != -1 )

System.out.print( (char)c );

f.close();

}

}

f.) La clase RandomAccessFile
Mediante los objetos de esta clase utilizamos ficheros binarios mediante un acceso aleatorio, tanto para lectura como para escritura. En estos ficheros hay un índice que nos dice en qué posición del fichero nos encontramos, y con el que se puede trabajar para posicionarse en el fichero.
Métodos de desplazamiento
Cuenta con una serie de funciones para realizar el desplazamiento del puntero del fichero. Hay que tener en cuenta que cualquier lectura o escritura de datos se realizará a partir de la posición actual del puntero del fichero.
• long getFilePointer();Devuelve la posición actual del puntero del fichero.
• void seek( long l ); Coloca el puntero del fichero en la posición indicada por l. Un fichero siempre empieza en la posición 0.
• int skipBytes( int n ); Intenta saltar n bytes desde la posición actual.
• long length(); Devuelve la longitud del fichero.
• void setLength( long l); Establece a l el tamaño de este fichero.
• FileDescriptor getFD(); Devuelve el descriptor de este fichero.
Métodos de escritura
La escritura del fichero se realiza con una función que depende el tipo de datos que se desee escribir.
• void write( byte b[], int ini, int len ); Escribe len caracteres del vector b.
• void write( int i ); Escribe la parte baja de i (un byte) en el flujo.
• void writeBoolean( boolean b ); Escribe el boolean b como un byte.
• void writeByte( int i ); Escribe i como un byte.
• void writeBytes( String s ); Escribe la cadena s tratada como bytes, no caracteres.
• void writeChar( int i ); Escribe i como 1 byte.
• void writeChars( String s ); Escribe la cadena s.
• void writeDouble( double d ); Convierte d a long y le escribe como 8 bytes.
• void writeFloat( float f ); Convierte f a entero y le escribe como 4 bytes.
• void writeInt( int i ); Escribe i como 4 bytes.
• void writeLong( long v ); Escribe v como 8 bytes.
• void writeShort( int i ); Escribe i como 2 bytes.
• void writeUTF( String s ); Escribe la cadena s utilizando la codificación UTF-8.
Los métodos que escriben números de más de un byte escriben el primero su parte alta.

Métodos de lectura
La lectura del fichero se realiza con una función que depende del tipo de datos que queremos leer.
• boolean readBoolean(); Lee un byte y devuelve false si vale 0 o true sino.
• byte readByte(); Lee y devuelve un byte.
• char readChar(); Lee y devuelve un caracter.
• double readDouble(); Lee 8 bytes, y devuelve un double.
• float readFloat(); Lee 4 bytes, y devuelve un float.
• void readFully( byte b[] ); Lee bytes del fichero y los almacena en un vector b.
• void readFully( byte b[], int ini, int len ); Lee len bytes del fichero y los almacena en un vector b.
• int readInt(); Lee 4 bytes, y devuelve un int.
• long readLong(); Lee 8 bytes, y devuelve un long.
• short readShort(); Lee 2 bytes, y devuelve un short.
• int readUnsignedByte(); Lee 1 byte, y devuelve un valor de 0 a 255.
• int readUnsignedShort(); Lee 2 bytes, y devuelve un valor de 0 a 65535.
• String readUTF(); Lee una cadena codificada con el formato UTF-8.
• int skipBytes(int n); Salta n bytes del fichero.
Si no es posible la lectura devuelven –1.

Ejemplo
Vamos a crear un pequeño programa que cree y acceda a un fichero binario, mediante acceso aleatorio.
El siguiente ejemplo crear un fichero binario que contiene los 100 primeros números (en orden):
// Crea un fichero binario con los 100 primeros numeros

static void creaFichBin( String ruta ) throws IOException {

RandomAccessFile f=new RandomAccessFile(ruta,"rw"); // E/S

for ( int i=1; i <= 100 ; i++ )

{

try{

f.writeByte( i );

} catch( IOException e){

// Gestion de excepcion de ejemplo

break; // No se puede seguir escribiendo

}

f.close();

}

}

El siguiente método accede al elemento cual de un fichero binario, imprimiendo la longitud del fichero, el elemento cual y su 10 veces siguiente elemento:
static void imprimeEltoN(String ruta, long cual)

throws IOException{

RandomAccessFile f=new RandomAccessFile(ruta,"r"); // E/

System.out.print( "El fichero " + ruta );

System.out.println( " ocupa " + f.length() + " bytes." );

f.seek( cual-1 ); // Me posiciono (-1 porque empieza en 0)

System.out.print(" En la posicion " + f.getFilePointer() );

System.out.println(" esta el numero " + f.readByte() );

f.skipBytes( 9 ); // Salto 9 => Elemento 10 mas alla

System.out.print(" 10 elementos más allá, esta el ");

System.out.println( f.readByte() );

f.close();

}

Si incluimos ambos métodos en una clase, y les llamamos con el siguiente programa principal (main()):
public static void main(String args[]) throws IOException {

String ruta="numeros.dat"; // Fichero

creaFichBin( ruta ); // Se crea

imprimeEltoN( ruta, 14 ); // Accedo al elemento 14.

}

Obtendremos la siguiente salida:
El fichero numeros.dat ocupa 100 bytes.
En la posicion 13 esta el numero 14
10 elementos más allá, esta el 24

6.4 Manejo de objetos persistentes

Las clases presistentes son clases en una aplicación que implementan las entidades del problema empresarial (por ejemplo, Customer y Order en una aplicación de comercio electrónico). No se considera que todas las instancias de una clase persistente estén en estado persistente. Por ejemplo, una instancia puede ser transitoria o separada.

Hibernate funciona mejor si estas clases siguen algunas reglas simples, también conocidas como el modelo de programación POJO (Plain Old Java Object). Sin embargo, ninguna de estas reglas son requerimientos rígidos. De hecho, Hibernate3 asume muy poco acerca de la naturaleza de sus objetos persistentes. Puede expresar un modelo de dominio en otras formas (por ejemplo, utilizando árboles de instancias de Map).

Ejemplo simple de POJO
La mayoría de aplicaciones Java requieren una clase persistente que represente a los felinos. Por ejemplo:
package eg;
import java.util.Set;
import java.util.Date;

public class Cat {
private Long id; // identifier
private Date birthdate;
private Color color;
private char sex;
private float weight;
private int litterId;
private Cat mother;
private Set kittens = new HashSet();
private void setId(Long id) {
this.id=id;
}
public Long getId() {
return id;
}
void setBirthdate(Date date) {
birthdate = date;
}
public Date getBirthdate() {
return birthdate;
}
void setWeight(float weight) {
this.weight = weight;
}
public float getWeight() {
return weight;
}
public Color getColor() {
return color;
}
void setColor(Color color) {
this.color = color;
}
void setSex(char sex) {
this.sex=sex;
}
public char getSex() {
return sex;
}
void setLitterId(int id) {
this.litterId = id;
}
public int getLitterId() {
return litterId;
}
void setMother(Cat mother) {
this.mother = mother;
}
public Cat getMother() {
return mother;
}
void setKittens(Set kittens) {
this.kittens = kittens;
}
public Set getKittens() {
return kittens;
}
public void addKitten(Cat kitten) {
kitten.setMother(this);
kitten.setLitterId( kittens.size() );
kittens.add(kitten);
}
}

Implemente un constructor sin argumentos

Cat tiene un contructor sin argumentos. Todas las clases persistentes deben tener un constructor predeterminado (el cual puede ser no-público) de modo que Hibernate pueda instanciarlas usando Constructor.newInstance(). Le recomendamos contar con un constructor por defecto con al menos una visibilidad de paquete para la generación de proxies en tiempo de ejecución en Hibernate.
Proporcione una propiedad identificadora (opcional)
Cat tiene una propiedad llamada id. Esta propiedad mapea a la columna de la llave principal de la tabla de la base de datos. La propiedad podría llamarse de cualquier manera y su tipo podría haber sido cualquier tipo primitivo, cualquier tipo de "wrapper" primitivo, java.lang.String o java.util.Date. Si su tabla de base de datos heredada tiene claves compuestas, puede utilizar una clase definida por el usuario con propiedades de estos tipos

La propiedad identificadora es estrictamente opcional. Puede olvidarla y dejar que Hibernate siga internamente la pista de los identificadores del objeto. Sin embargo, no recomendamos que esto suceda.
De hecho, algunas funcionalidades se encuentran disponibles sólamente para clases que declaran una propiedad identificadora:
Session.saveOrUpdate()
Session.merge()
Le recomendamos que declare propiedades identificadoras nombradas-consistentemente en clases persistentes. y que utilice un tipo nulable (por ejemplo, no primitivo).
Prefiera las clases no finales
Un aspecto central de Hibernate, los proxies, dependen de que las clases persistentes sean no finales o de la implementación de una interfaz que declare todos los métodos públicos.
Con Hibernate puede persistir las clases finales que no implementen una interfaz. Sin embargo, no podrá utilizar proxies para recuperación perezosa de asociaciones, lo cual limitará sus opciones para afinar el rendimiento.
También debe evitar el declarar métodos public final en las clases no-finales. Si quiere utilizar una clase con un método public final, debe deshabilitar explícitamente el uso de proxies estableciendo lazy="false".
Declare métodos de acceso y de modificación para los campos persistentes
Cat declara métodos de acceso para todos sus campos persistentes. Muchas otras herramientas ORM persisten directamente variables de instancia. Es mejor proporcionar una indirección entre el esquema relacional y las estructuras de datos internos de la clase. Por defecto, Hibernate persiste las propiedades del estilo JavaBeans, y reconoce los nombres de método de la forma getFoo, isFoo y setFoo. De ser necesario, puede cambiarse al acceso directo a campos para propiedades específicas.
No es necesario declarar públicas las propiedades. Hibernate puede persistir una propiedad con un par get / set protected o private.

Implementación de herencia
Una subclase también tiene que cumplir con la primera y la segunda regla. Hereda su propiedad identificadora de la superclase Cat. Por ejemplo:
package eg;
public class DomesticCat extends Cat {
private String name;
public String getName() {
return name;
}
protected void setName(String name) {
this.name=name;
}
}
Implementando equals() y hashCode()
Tiene que sobrescribir los métodos equals() y hashCode() si:
piensa poner instancias de clases persistentes en un Set (la forma recomendada de representar asociaciones multivaluadas); y
piensa utilizar reasociación de instancias separadas.
Hibernate garantiza la equivalencia de identidad persistente (fila de base de datos) y de identidad Java sólamente dentro del ámbito de una sesión en particular. De modo que en el momento en que mezcla instancias recuperadas en sesiones diferentes, tiene que implementar equals() y hashCode() si desea tener una semántica significativa para Sets.

La forma más obvia es implementar equals()/hashCode() comparando el valor identificador de ambos objetos. Si el valor es el mismo, ambos deben ser la misma fila de la base de datos ya que son iguales. Si ambos son agregados a un Set, sólo tendremos un elemento en el Set). Desafortunadamente, no puede utilizar este enfoque con identificadores generados. Hibernate sólo asignará valores identificadores a objetos que son persistentes; una instancia recién creada no tendrá ningún valor identificador. Además, si una instancia no se encuentra guardada y está actualmente en un Set, al guardarla se asignará un valor identificador al objeto. Si equals() y hashCode() están basados en el valor identificador, el código hash podría cambiar, rompiendo el contrato del Set. Consulte el sitio web de Hibernate y allí encontrará una discusión completa sobre este problema. Este no es un problema de Hibernate, sino de la semántica normal de Java de identidad de objeto e igualdad.
Le recomendamos implementar equals() y hashCode() utilizando igualdad de clave empresarial (Business key equality). Igualdad de clave empresarial significa que el método equals() sólamente compara las propiedades que forman la clave empresarial. Esta es una clave que podría identificar nuestra instancia en el mundo real (una clave candidata natural):

public class Cat {
public boolean equals(Object other) {
if (this == other) return true;
if ( !(other instanceof Cat) ) return false;
final Cat cat = (Cat) other;
if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
if ( !cat.getMother().equals( getMother() ) ) return false;
return true;
}
public int hashCode() {
int result;
result = getMother().hashCode();
result = 29 * result + getLitterId();
return result;
}
}
Modelos dinámicos
Las entidades persistentes no necesariamente tienen que estar representadas como clases POJO o como objetos JavaBean en tiempo de ejecución. Hibernate también soporta modelos dinámicos (utilizando Mapeos de Mapeos en tiempo de ejecución) y la representación de entidades como árboles de DOM4J. No escriba clases persistentes con este enfoque, sólamente archivos de mapeo.
Los siguientes ejemplos demuestran la representación utilizando Mapeos. Primero, en el archivo de mapeo tiene que declararse un entity-name en lugar de, o además de un nombre de clase:

type="long"
column="ID">

column="NAME"
type="string"/>

column="ADDRESS"
type="string"/>

column="ORGANIZATION_ID"
class="Organization"/>

inverse="true"
lazy="false"
cascade="all">

>
Aunque las asociaciones se declaran utilizando nombres de clase destino, el tipo destino de una asociación puede ser además una entidad dinámica en lugar de un POJO.
Después de establecer el modo de entidad predeterminado como dynamic-map para la SessionFactory, puede trabajar en tiempo de ejecución con Mapeos de Mapeos:

Session s = openSession();
Transaction tx = s.beginTransaction();
// Crea un cliente
Map david = new HashMap();
david.put("name", "David");

// Crea una organizacion
Map foobar = new HashMap();
foobar.put("name", "Foobar Inc.");

// Liga ambos
david.put("organization", foobar);

// Guarda ambos
s.save("Customer", david);
s.save("Organization", foobar);

tx.commit();
s.close();
Una de las ventajas principales de un mapeo dinámico es el rápido tiempo de entrega del prototipado sin la necesidad de implementar clases de entidad. Sin embargo, pierde el chequeo de tipos en tiempo de compilación y muy probablemente tendrá que tratar con muchas excepciones en tiempo de ejecución. Gracias al mapeo de Hibernate, el esquema de base de datos se puede normalizar y volver sólido, permitiendo añadir una implementación apropiada del modelo de dominio más adelante.
Los modos de representación de entidad se pueden establecer por Session:
Session dynamicSession = pojoSession.getSession(EntityMode.MAP);

// Crea un cliente
Map david = new HashMap();
david.put("name", "David");
dynamicSession.save("Customer", david);
...
dynamicSession.flush();
dynamicSession.close()

more...
No comment yet.