Práctica 3 (TSIOCA 2007-2008)


Fecha
07-03-2008
Título
Orientación a Objetos I
Conceptos
Abstracción, Encapsulación, Conceptos de Clases (atributos, constructores, métodos), Uso de paquetes de la API de Java.
Soluciones
SolucionesP3.zip
Profesores
Alberto CortésPablo Basanta (mañana),   Jorge Ruiz y José María Rubio (tarde).

 

Ejecicio 0. - Repaso de Objetos.


En esta serie de prácticas (3,4, y 5) vamos a practicar con conceptos de Programación Orientada a Objetos (POO), pero antes de abordar dichos temas, conviene hacer un primer repaso para refrescar unas ideas básicas que es necesario tener a la hora de trabajar con clases y objetos. Para ello, descarga la siguiente clase Punto que ya está implementada. Tras analizarla, responde a las siguientes preguntas básicas a la hora de trabajar con objetos de esta clase:

Ahora, para comprobar que sabemos trabajar con objetos, crea un sencillo programa PruebaObjeto que realice las siguientes tareas con objetos de la clase Punto:
  1. Crea dos objetos (p1,p2) de la clase Punto inicializados con los valores que quieras.
  2. Imprime por pantalla la cadena de caracteres con la representación del objeto p1.
  3. Imprime por pantalla las coordenadas del punto p1.
  4. Imprime por pantalla la distancia del punto p1 al origen.
  5. Imprime por pantalla la distancia del punto p1 al punto p2.
  6. Imprime por pantalla el número de objetos que se han creado de la clase Punto.

Pues bien, ya estamos preparados para introducirnos realmente en la práctica en sí. Si no te da tiempo a hacerla en clase, termínala en casa.

Introducción

La Programación Orientada a Objetos (POO) permite representar los conceptos con los que trabajamos en la realidad creando modelos de objetos que los simulan. Los objetos son la base de la POO. Los principios fundamentales de la POO son: abstracción,encapsulación,herencia y polimorfismo. En esta práctica vamos a centrarnos en los dos primeros.


El objetivo final de esta práctica es conseguir que nuestros programas puedan obtener información útil objetos que haya “en ejecución” en esos momentos, una especie de Analizador de objetos que nos permita respondernos a preguntas del tipo: ¿cuantas instancias hay de un determinado objeto? ¿de qué clase es?, ¿cuántos atributos tiene? ¿y cuales son sus modificadores de acceso asociados? ¿cuáles son sus métodos?, etc... Toda esta información es la que se conoce con el nombre de "metadatos" o "meta-información" de los objetos.


Pues bien, aplicando los principios mencionados anteriormente, vamos a modelar toda esa información que está asociada a cualquier objeto. Para ello, observa la estructura de la siguiente clase Ejemplo que define la plantilla de todos los objetos de dicho tipo que se instancien en la ejecución de un programa:


class Ejemplo{

    public  int  atributo1;
    private String atributo2;

    public Ejemplo () {...}
    public Ejemplo (int parametro) {...}

    public static void metodo1() {...}
    protected int metodo1( int parametro ) {...}

}

Si se analiza la estructura de Ejemplo, observa que está estructurada de la siguiente manera:

Pues bien, vamos a “abstraer” y "encapsular" toda esta información que hemos analizado. Para ello, crearemos las siguientes clases que nos permitan almacenar y acceder, respectivamente, a la informacion relativa a los atributos, constructores y métodos de un objeto cualquiera:


·      Atributo.java

·      Constructor.java

·      Metodo.java

Siguiendo el mecanismo anterior, una Clase, en sentido genérico, es una especie de contenedor de toda la anterior información (atributos, constructores y métodos) relativa un objeto. Pues bien, para modelarlo, abstraeremos y encapsularemos toda la anterior información en la siguiente clase que se llama igual, valga la redundancia:

·      Clase.java

Ya que el objetivo final de la práctica es poder recolectar y analizar toda la información de nuestros objetos en tiempo de ejecución, crearemos una nueva clase que permitirá extraera y procesala. En esta práctica, nos interesará obtenter la siguiente información asociada a un objeto: la información de la clase del mismo,  el "alias" (nombre alternativo) del objeto y el número de instancias del objeto en ejecución que se han analizado. Todo ello lo implementará la clase AnalizadorObjeto que almacenará toda la información:


·      AnalizadorObjeto.java


Por último, para probar todo esto, construiremos finalmente un programa de prueba que cree una serie de objetos de cualquier clase para, posteriormente, obtener la información de los mismos (metadatos) "en tiempo de ejecución". Para ello, implementaremos la siguiente clase:


·      PruebaObjetos.java


NOTA: Para crear las instancias de nuestros objetos de prueba, usaremos las dos clases de ejemplo que se proporcionan y que nos servirán para crear las instancias de los respectivos objetos de nuestra práctica y podremos comprobar toda la información que nos proporcione el análisis que hagamos de ellos. Para ello, se usarán las siguientes clases de prueba que puedes descargar de los siguientes enlaces:


·      ClasePrueba.java  

·      OtraClasePrueba.java  


¡¡ NOTA IMPORTANTE !! - Aunque, a priori, la práctica parezca complicada, no te preocupes, se proporciona casi todo el código fuente de la misma. Los métodos que se pide implementar son sencillos. Es importante que entiendas el concepto y el sentido del código que se proporciona ya implementado. La siguiente práctica (herencia) se basa en los resultados de esta y se reutilizarán en ellas algunas clases.  

 

NOTA: Por si sientes curiosidad, los métodos que ya están implementados en la practica son los que realmente acceden a una de una de las características más curiosas de Java y que permite tener la capacidad obtener información de cualquier objeto que se está ejecutando en un programa y, lo más curioso de todo, "sin tener acceso al código fuente de la clase del mismo" gracias al mecanismo que proporciona Java para ello conocido como "introspección"  (Reflection).


Ejercicio 1. La clase Modificador (modificadores de acceso).


Esta clase no tienes que implementarla y simplemente tienes que saber para qué sirve. Contiene la información sobre los diversos modificadores de acceso asociados a cualquier miembro de un objeto y que, ya que son invariables, se definen por las siguientes constantes enteras:

    public static final int PUBLIC = 1;
    public static final int PRIVATE = 2;
    public static final int PROTECTED = 4;
    public static final int STATIC = 8;
    public static final int FINAL = 16;
    public static final int SYNCHRONIZED = 32;
    public static final int VOLATILE = 64;
    public static final int TRANSIENT = 128;
    public static final int NATIVE = 256;
    public static final int INTERFACE = 512;
    public static final int ABSTRACT = 1024;
    public static final int STRICT = 2048;

Como ves, a  cada una de las constantes se le asocia la cadena de caracteres con el literal correspondiente de la siguiente lista de modificadores de Java:

abstract, final, interface, native, private, protected, public, static, strict, synchronized, transient, volatile.

Los modificadores de acceso se identifican con un número entero que representa una combinación de las anteriores constantes. Para obtener el literal asociado a unos modificadores de acceso, la clase define el siguiente método estático que permite obtener una cadena descripción literal del modificador que se le pasa como parámetro:

    public static String toString( int modifcador );

NOTA: Observa que se ha resaltado, en negrita, los modificadores de acceso asociado al método en sí, toString(), para que comprendas de lo que estamos tratando:

Para probar esta clase, descárgala desde el siguiente enlace: Modificador.java , compílala y ejecútala pasándole como argumento un número entero que coincida con alguna de las constantes anteriores (por ejemplo: 1) y observa el resultado. Para obtener una combinación de modificadores tendrás que pasarle como argumento, un número entero que corresponda con la suma de las constantes correspondientes (por ejemplo: 24) y observa el resultado.

Cuestiones para responder en casa:


Ejercicio 2.  La clase Atributo.

La clase Atributo contiene la información relativa a un atributo de cualquier objeto en ejecución. El aspecto de la misma es el siguiente:

public class Atributo {
   
    public String  nombre = null;
    public String tipo = null;
    public int modificadores = 0;
   
    public Atributo(String nombre, String tipo, int modificadores ) { /*...*/}
   
    public String toString() {/*...*/}
}

Donde nombre es el nombre del atributo, tipo es el tipo del atributo y modificadores es el número entero asociado a los modificadores de acceso asociado a dicho atributo (ver Ejercicio 1). Todos los atributos son públicos a la hora de acceder a ellos.
Esta clase tiene declarados los siguientes métodos que permiten crear e imprimir las instancias de Atributo:           

-        Un constructor de Atributo con los parámetros adecuados.

-        Un método públic String toString() que permite obtener una cadena de caracteres con una descripción literal del atributo correspondiente mostrando los siguientes datos del mismo: el nombre, el tipo y el modificador de acceso. Un formato de ejemplo puede ser el siguiente: 

   ATRIBUTO : NOMBRE=<nombre_Atributo> TIPO =java.lang.String MODIFICADOR ACCESO = public

 

Nota: Recuerda que, para obtener el literal asociado a los modificadores de acceso tienes que hacer uso del método toString() correspondiente de la clase Modificador que has descargado anteriormente.

En este ejercicio, se pide implementar estos dos métodos. Para ello, descarga el esqueleto de la clases Atributo del siguiente enlace y modifícalo: Atributo.java



Ejercicio 3. Las clases Metodo y Constructor.

La clase Metodo contiene la información asociada a un método de un objeto en ejecución. La diferencia con un Atributo radica en que un método tiene asociado un tipo de retorno que se refleja en el atributo correspondiente. El aspecto de la misma es es siguiente :

public class Metodo {
   
    public String nombre;
    public int modificadores;
    public String tipoRetorno;
   
    public Metodo(String nombre, int modificadores, String tipoRetorno) {/*...*/}
   
    public String toString() {/*...*/}
}

Donde nombre es el nombre del método, modificadores representa a los modificadores de acceso y tipoRetorno contiene el tipo de retorno del método. Todos los atributos son de acceso público.

La clase Constructor se diferencia de la anterior en que, a diferencia de un método, el constructor de cualquier objeto no tiene ningún tipo de retorno asociado al mismo, lo que implica que no existe dicha información y el atributo correspondiente. El aspecto es el siguiente:

public class Constructor {
   
    public String nombre;
    public int modificadores;

    public Constructor(String nombre, int modificadores) { /*...*/ }
   
    public String toString() { /*...*/ }
 
}
Donde nombre es el nombre del constructor y modificadores es el entero asociado a los modificadores de acceso asociados al Constructor.

Todos los atributos son de acceso público. Al igual que las anteriores clases, tanto Metodo como Constructor tienen los siguientes métodos que permiten crear y acceder a las instancias de los mismos:           

-        Un constructor con los parámetros correspondientes.

-        Un metodo públic String toString() que devuelve una cadena de caracteres y permite tener una descripción del objeto de la clase mostrando los siguientes datos: el nombre, el tipo de retorno (si tiene) y los modificadores de acceso de mismo.Un formato de ejemplo puede ser el siguiente (para cada clase):

    METODO : NOMBRE=<nombre_MetodoPublico> MODIFICADOR ACCESO= public TIPO RETORNO =void

    CONSTRUCTOR : NOMBRE=<nombre_Constructor> MODIFICADOR ACCESO= public

    
Nota: Para obtener el literal asociado a los modificadores de acceso tienes que hacer uso de la clase Modificador que has descargado anteriormente.

Para este ejercicio, se pide implementar estos métodos en cada una de las respectivas clases Metodo y Constructor. Descárgalas de los siguientes enlaces y modifícalas: Metodo.java y Constructor.java

 


 

Ejercicio 4. La nueva clase Clase.

Esta nueva clase reune toda la información que hemos modelado en las clases anteriores relativa a los objetos que están en ejecución. Su aspecto es el siguiente:

public class Clase {
   
    String nombre;
    private Atributo[] atributos;
    private Constructor[] constructores;
    private Metodo[] metodos;


    public Clase( Object o ) {/*...*/}
   
    public Atributo[] getAtributos() {/*...*/}
    public Constructor[] getConstructores() {/*...*/}

    public Metodo[] getMetodos() {/*...*/}
    public String toString() {/*...*/}
}

Tal y como se enunció en la introducción de la práctica, una Clase tiene las siguientes características: un nombre, y una serie de miembros que pueden ser: atributos, constructores y métodos. Pues bien, esta nueva Clase abstrae y encapsula toda esa información como colecciones (arrays) de objetos de las clases anteriores en los respectivos atributos de la misma. Se ha establecido que la única información de acceso público para este tipo de objetoe es el nombre mientras que el resto permanece privado. Como puedes observar, la clase contiene además los siguientes métodos:

-        Un constructor Constructor al que se le pasa como parámetro la instancia del objeto sobre el cual se va a obtener la información. 

-        Un método public Atributo[] getAtributos() que permite obtener el array con los Atributos de la clase.

-        Un método public  Constructor[] getConstructores() que permite obtener el array con los Constructores de la clase.

-        Un método public Metodo[] getMetodos() que permite obtener el array con los Métodos de la clase.

-        Un metodo public String toString() que devuelve una cadena de caracteres y permite tener una descripción del objeto de la clase con los valores del nombre y los datos asociados de todos los miembros de la misma, es decir, de los atributos, los constructores y los métodos.

 

Nota: para implementar este método tendrás que recorrer los arrays correspondientes e invocar al los métodos toString() correspondientes. Recuerda que lo que se debe devolver en este método es una cadena de caracteres (String) que se usará cuando se quiera imprimir por pantalla la información de la clase.

 

¡¡ NOTA IMPORTANTE !!: El Constructor de la clase ya está implementado y no tienes que hacer nada, solo sirve para que observes cómo se usan las clases del paquete java.lang.reflect del API de Java que es el que permiten obtener realmente la información que necesitamos de nuestro objeto en ejecución. Intenta comprender el código ya que te será de utilidad a la hora de abordar la siguiente práctica que está basada en esta.

En este ejercicio, se pide implementar los métodos de acceso y el método toString(). Para ello, descarga el código de la Clase del siguiente enlace y modifícalo de acuerdo a las indicaciones:  Clase.java

 

Ejercicio complementario para hacer en casa:


Para implementar el constructor de Clase, se han usado las clases del paquete java.lang.reflect del API de Java, más en concreto las siguientes clases: Class, Field, Modifier, Constructor y Method. Para entender el uso de estas clases, algunos de los siguientes ejemplos que te ayudarán a comprender cómo se usan:


  


 

Ejercicio 5. La clase AnalizadorObjeto.

Esta clase es la que realmente recoge y analiza la información de cualquier objeto que creemos en esta práctica. El aspecto de la misma es el siguiente:


public class AnalizadorObjeto {

    private Clase clase;
    public String alias;
    public static int contador;
   
    public AnalizadorObjeto (Object o) {/*...*/}
    public AnalizadorObjeto ( Object o, String alias ) {/*...*/}

   

    public Clase getClase(){/*...*/}
    public String toString() {/*...*/}
   
}

La información que va a almacenar cualquier Analizador de Objetos que creemos es la siguiente: 

-        La información de la clase del objeto que queremos analizar (de sus atributos, métodos, constructores). Esta información es privada.

-        El nombre alternativo asociado que asociemos a dicho objeto, es decir, un “alias”. Es de acceso público.

-        Un contador del número total de instancias de objetos de tipo AnalizadorObjeto creados en un programa. Es de acceso público.

Para acceder a dicha información del objeto, se definen los siguientes métodos del interfaz de acceso asociado a cualquier Analizador de Objetos y que permite acceder a la información privada del mismo:


-        Un método public Clase getClase() que permite obtener la clase de dicho objeto.

-      Un metodo public String toString() que permita tener una descripción literal de la información del objeto de la misma forma que hemos hecho antes. Para ello, tendrás que usar el método toString() que has definido en las clases anteriores.

 

Nota: El constructor de AnalizadorObjeto tiene un parámetro, O , que es el objeto que vamos a analizar. Recuerda que cualquier objeto en Java deriva de la clase Object, por lo que el constructor de Objeto permite ser invocado con cualquier objeto de cualquier clase. Será en el último ejercicio donde se instancien dichas clases (ClasePrueba.java, OtraClasePrueba.java)

Al igual que en las clases anteriores, se pide implementar estos métodos. Para ello, descarga el código de Objeto del siguiente enlace y modifícalo: AnalizadorObjeto.java



Ejercicio 6.  La clase PruebaObjetos.

 

Nota: Para compilar este ejercicio necesitarás tener acceso a las clases de prueba que puedes descargar de los siguientes enlaces: ClasePrueba.java y OtraClasePrueba.java

¡¡ Por fin, hemos llegado a la prueba final de esta práctica!!. Tras haber creado todas estas clases, este va a ser el programa principal de la práctica que va a permitir demostrar el objetivo inicial de esta práctica y que consistía en obtener información en tiempo de ejecución sobre el tipo (la clase) de un objeto que esté instanciado en un instante determinado. Para ello, crea una clase PruebaObjetos que tenga un método main que realice las siguientes tareas: 

  1. Crear dos objetos respectivamente de la clase ClasePrueba y OtraClasePrueba respectivamente.
  2. Crea dos objetos respectivamente de la clase AnalizadorObjeto a partir de los objetos anteriores.
  3. Imprimir la información de los objetos que proporciona la clase AnalizadorObjeto.
  4. Imprimir el número total de objetos analizados.


El resultado de la práctica debe ser algo parecido a esto:

E:\uni\tsioca\practica03\soluciones>java PruebaObjetos
 INFORMACIËN DE OBJETOS EN EJECUCIËN:
***********************
 La meta-informaci¾n 'en tiempo de ejecuci¾n' del OBJETO
ClasePrueba@1004901 es:
OBJETO:  alias=no tiene
CLASE: ClasePrueba
ATRIBUTO : NOMBRE=atributoPublico TIPO =java.lang.String MODIFICADOR ACCESO = public
ATRIBUTO : NOMBRE=atributoProtegido TIPO =int MODIFICADOR ACCESO = protected
ATRIBUTO : NOMBRE=atributoPrivado TIPO =char MODIFICADOR ACCESO = private
CONSTRUCTOR : NOMBRE=ClasePrueba MODIFICADOR ACCESO= public
CONSTRUCTOR : NOMBRE=ClasePrueba MODIFICADOR ACCESO= public
METODO : NOMBRE=metodoPublico MODIFICADOR ACCESO= public TIPO RETORNO =void
METODO : NOMBRE=metodoProtegido MODIFICADOR ACCESO= protected TIPO RETORNO =void
METODO : NOMBRE=metodoPrivado MODIFICADOR ACCESO= private TIPO RETORNO =void
***********************
 La meta-informaci¾n 'en tiempo de ejecuci¾n' del OBJETO
OtraClasePrueba@18fe7c3 es:
OBJETO:  alias=no tiene
CLASE: ClasePrueba
ATRIBUTO : NOMBRE=atributoPublico TIPO =java.lang.String MODIFICADOR ACCESO = public
ATRIBUTO : NOMBRE=atributoProtegido TIPO =int MODIFICADOR ACCESO = protected
ATRIBUTO : NOMBRE=atributoPrivado TIPO =char MODIFICADOR ACCESO = private
CONSTRUCTOR : NOMBRE=ClasePrueba MODIFICADOR ACCESO= public
CONSTRUCTOR : NOMBRE=ClasePrueba MODIFICADOR ACCESO= public
METODO : NOMBRE=metodoPublico MODIFICADOR ACCESO= public TIPO RETORNO =void
METODO : NOMBRE=metodoProtegido MODIFICADOR ACCESO= protected TIPO RETORNO =void
METODO : NOMBRE=metodoPrivado MODIFICADOR ACCESO= private TIPO RETORNO =void
***********************
 NUMERO TOTAL DE OBJETOS ANALIZADOS: 2
***********************


 

Ejercicio complementario para hacer en casa.


Como ejercicio complementario para hacer en casa, haz lo siguiente:

  1. Crea una nueva clase de ejemplo (ClasePrueba2.java) que tenga todo tipo de miembros
  2. Modifica el programa anterior PruebaObjetos para que instancie un objeto de esta clase.
  3. Comprueba cómo también funciona para ella e imprime todos los datos asociados a la misma.

Por último, realiza otra prueba instanciando cualquier clase del API de Java y comprobando el resultado.