G.Bordel >Docencia >TAP Técnicas Actuales de Programación (curso 2010-2011)
desprotegido Intro. desprotegido Temario desprotegido Calendario desprotegido RPF desprotegido Recursos protegido Práctica protegido Gest. Alum.
tema_anterior Tema 6: El contenido de la biblioteca de clases tema_siguiente
  1. Introducción.
  2. El paquete java.lang.[ejercicios]
  3. Clases de utilidad (java.util) /iterator/.[ejercicios]
  4. Genéricos.[ejercicios]
  5. Ademdum: 1) uso de bibliotecas externas; 2) patrones diversos;.[ejercicios]

6.2- El paquete java.lang

El paquete Java.lang (esto no incluye a sus subpaquetes), es el que contiene clases básicas e imprescindibles para el desarrollo de software con Java. Este hecho implica que en la escritura de toda clase nos veríamos obligados a "importar" este paquete (recuérdese el tema 2) de modo que el compilador reconociese el uso de elementos contenidos en él. En realidad no es así porque, al ser imprescindible, el sistema lo importa siempre de modo automático. Por tanto la realidad es que nunca importaremos explícitamente este paquete.<

Estudiamos a continuación los principales elementos de su contenido.

(1) La clase Object

Object es la clase raíz de la jerarquía de herencia, y por tanto los elementos que en ella se definen son transmitidos a todas las demás clases. En la construcción de cualquier clase hemos de tener en cuenta que recibe esta herencia y debemos determinar si admitirla tal cual o si será necesario re-escribir algunos elementos. Antes de invitar al alumno a que eche un vistazo a la documentación de esta clase haremos algunas observaciones que orienten su inspección:

  • El método clone está definido para permitir la clonación (la duplicación) de objetos. En realidad éste método en su implementación dentro de Object sólo devuelve un apuntador al mismo objeto (es decir, no duplica), no cumpliendo la mencionada funcionalidad, ya que en realidad cada clase debe reescribirlo para que la duplicación se realice adecuadamente. No obstante, no necesariamente toda clase debe permitir la clonación y por ello en caso de que esta sea posible, debemos explicitarlo declarando la implementación del interfaz Cloneable. La declaración de éste interfaz no implica la inclusión de ningún método, ya que se trata de un interfaz vacío con una única función de control por parte del compilador de la funcionalidad que nos ocupa.

    1-  public class MiClaseClonable implements Cloneable {
    2-   
    3-    public MiClaseClonable clone() {
    4-        //instanciación y copia de contenidos del objeto para formar una copia
    5-        return <el nuevo objeto> 
    6-    }
    7-   
    8-  //Otros métodos de la clase
    9-   
    10-  }
  • El método equals tiene por misión permitir comparar dos objetos. Sucede con él lo mismo que sucede con clone, que no esta realmente implementado según esta idea dentro de Object sino que debe reescribirse en cada nueva clase. La nueva reescritura que hagamos deberá ser consistente conuna relación de equivalencia, es decir, ser reflexiva, transitiva, y simétrica además de ser consistente (no variar si no hay cambios en los elementos implicados en cada objeto). En el caso de Object este método devuelve true no cuando se aplica a dos objetos iguales, sino al mismo objeto (s.equals(t) es true si s y t son el mismo objeto)

    Una comparación entre dos objetos no implicará normalmente que absolutamente toda su composición sea idéntica, sino que habrá elementos internos que no participen de la comparación (muchos de ellos son los no puestos explícitamente por el programador).

  • El método toString debe devolver una String representativa del objeto. Esta capacidad es importante por diversos motivos, pero resaltaremos el hecho de que cualquier operación de "impresión" de un objeto llama automáticamente a esta función de modo que, por un lado esto supone una comodidad importante (los objetos como tal son "imprimibles") y por otro es un importante soporte a la hora de desarrollar software (al disponer de representaciones de los objetos en situaciones en que debemos examinarlos para descubrir causas de errores). El método toString en la clase Object devuelve una String con la dirección del objeto (nos permitirá por tanto saber si dos apuntadores se refieren al mismo o a diferentes objetos).

  • El método finalize se ejecuta cuando el sistema (el hilo "recogedor de basuras" como veremos en un capítulo posterior) determina que un objeto puede ser eliminado. Por tanto este es un método que podremos escribir pero no será para utilizarlo por nosotros mismos. Este método será necesario si nuestro objeto mantiene algun tipo de recurso que debe liberar antes de desaparecer (p.ej. una determinada información en una estructura de datos). Esta no es la situación más habitual por lo que la necesidad de escribir un método finalize es poco corriente.

  • El método hashcode es la "función de hash" utilizada en numerosas estructuras de datos para obtener un crecimiento equilibrado de las mismas al aumentar la cantidad de elementos que almacenan. Dentro de la biblioteca estándar, principalmente en las "colecciones" del paquete java.util encontramos estructuras que hacen uso de ella. La condición necesaria de una función de hash es que elementos iguales proporcionen el mismo entero, de una forma consistente entre diversas ejecuciones de la aplicación (es decir, siempre el mismo). La consideración de "iguales" para dos objetos será la misma que haga la función equals. La función hashcode de clase Object devuelve un entero relacionado con la dirección en meemoria del objeto, de modo que no es normalmente una función de hash correcta y deberá ser redefinida en nuestras clases en caso de que vayamos a necesitarla.
  • El método getClass devuelve un objeto de la clase Class que incluye información de la clase a la que pertenece nuestro objeto y posibilita acceder a toda una serie de capacidades denominadas de "Reflexión" que proporcionan información sobre su estructura y capacidades (básicamente en el paquete java.lang.Reflect).
  • Los métodos notify, notifyAll, y wait tienen una funcionalidad relacionada con la programación en paralelo y serán estudiados en el tema correspondiente.

Una vez vistas estas consideraciones puede estudiar la documentación de Object

(2) La clase System

La clase System, al igual que sucede con Object, es también particularmente interesante. En ella encontramos métodos que nos permiten acceder a elementos del sistema en que corre nuestra aplicación. En primer lugar debemos mencionar que dentro de esta clase nos encontramos con la entrada y las salidas estándar y de error (normalmente, si no hay redireccionamientos, serán el teclado y la pantalla de nuestra máquina). La entrada estándar es un objeto que pertenece a esta clase y se denomina in, y en salida disponemos de los objetos out y err. Estos objetos son de clases que se verán más adelante, pero recordemos que ya nos encontramos con ellos a modo de avance necesario en momentos muy tempranos de este curso:

1-  //
2-  // Aplicación ejemplo "HolaMundo"
3-  //
4-   
5-   public class HolaMundo {
6-     public static void main(String[] args) {
7-       System.out.println("Hola, mundo");
8-    }
9-   }

Además de estos elementos, encontraremos aquí una serie de métodos del máximo interés:

  • currentTimeMillis y nanoTime nos proporcionan una representación numérica del instante en que son ejecutadas, de modo que son de utilidad para medir tiempos de ejecución del código.
  • getenv nos permite acceder a variables de entorno del sistema
  • getProperty, getProperties, setProperty, setProperties y clearProperty son de utilidad para acceder y establecer propiedades del sistema (en la documentación de getProperties encontramos una lista de estas propiedades)
  • exit es el método que termina con la ejecución de la aplicación.
  • arraycopy permite copiar contenidos de porciones de arrays en otros o en distintas zonas del mismo.
  • setIn, setOut y setErr permiten redireccionar las entradas y salidas estándar.
  • Otras funciones nos permiten acceder al gestor de seguridad, cargar librerias de un modo explícito, ejecutar finalizadores,i ejecutar el recolector de basuras (que retira los objetos en desuso como veremos en el tema de hilos), etc.
(3) Objetos asociados a tipos primitivos.

Java es un lenguaje orientado a objeto hibrido por mantener los tipos de datos primitivos. Estos datos primitivos se mantienen por razones de eficacia en expresiones, ya que el uso de objetos supone un sobrecoste computacional que en el caso de la evaluación de expresiones puede resultar excesivamente gravoso. Para conectar el mundo de los objetos con el de las variables de tipos primitivos se dispone de una clase asociada a cada tipo primitivo. Cada una de estas clases proporciona métodos para pasar de un espacio a otro asi como utilidades relacionadas (por ejemplo conversiones de números en formato texto a variables del tipo correspondiente). En general la denominación de estas clases es idéntica a la de los tipos primitivos correspondientes, si bien su primera letra es mayúscula, a excepción de los casos de Integer y Character. Todos estos tipos (y alguno más relacionado) son descendientes de la clase abstracta Number; éste puede ser un buen ejemplo de utilidad de las clases abstractas que el alumno puede examinar estudiando su documentación.

Mencionaremos aquí también como ejemplo de alguna de las características estudiadas con anterioridad, que la clase Character contiene dos clases internas, por lo que es interesante revisar su documentación para estudiar este caso concreto.


(4) Cadenas de caracteres.

Dentro de java.lang encontramos también la clase String que, como sabemos, es la cadena de caracteres. Es interesante darse cuenta de lo "especial" que es esta clase por su utilidad por el hecho de que todos los lenguajes no orientados a objetos disponen de un tratamiento específico para las cadenas de caracteres con métodos e incluso operadores que actúan sobre ellas de modo que son tratadas en realidad de un modo muy próximo a lo que son los objetos.

En Java no obstante, disponemos de otra clase relacionada: StringBuffer, y desde la versión 1.5 de una más aún: StringBuilder. Es preciso que distingamos la funcionalidad de cada una de ellas:

  • String representa a una cadena de caracteres inmutable, es decir, una vez construida no puede variar, y todas las funciones que actuan sobre ella son, o bien de análisis de la misma (ver si contiene a otra, si es igual a otra, etc) o bien de extracción de una nueva String (p.ej. una parte de ella, o una versión en minusculas, etc). Es aconsejable echar un vistazo a la larga lista de funciones y constructores disponibles en esta clase.
  • StringBuffer representa a una cadena de caracteres mutable, es decir, en este caso podemos alterar la cadena de caracteres tanto en el contenido de sus distintas posiciones de almacenamiento de caracteres como en su longitud. Es muy utilizada para la construcción de cadenas por concatenación de segmentos mediante el método append. Esta capacidad de mutación de esta clase es muy conveniente, pero siempre debemos tener en cuenta al utilizarla que esta soportada por la clase String (es decir, p.ej. un append en es realidad una conversión a String, una concatenación con la cadena dada y una nueva conversión a StringBuffer del resultado), por lo que estas operaciones son costosas computacionalmente y no debe abusarse de ellas en la medida de lo razonable.
  • StringBuilder ha sido introducida en la versión 1.5 como clase de sustitución de StringBuffer en determinadas ocasiones. Esta sustitución es conveniente siempre que sea posible puesto que esta nueva clase es computacionalmente más ligera que la anterior. La diferencia estriba en algo que por el momento no hemos estudiado en este curso pero que podemos adelantar someramente: nuestros programas en Java pueden poner en marcha hilos de ejecución (por explicarlo de algun modo tareas en paralelo), y si nuestra cadena de caracteres es accedida por más de uno de estos hilos deberá ser un StringBuffer, mientras que si sólo uno de ellos va a acceder podremos utilizar un StringBuilder. La diferencia estriba en que StringBuffer implementa mecanismos de "sincronización" entre hilos que StringBuilder se "ahorra". Naturalmente las String pueden usarse sin problemas ya que al no ser mutables no presentan problemas de interacción en el caso de que sean accedidas por más de un hilo de ejecución.
(5) Funciones matemáticas.

Disponemos en java.lang de dos clases relacionadas con las operaciones matemáticas: Math y StrictMath. En ambos casos se trata de clases que algunos denominan como "clases maleta", esto quiere decir que simplemente son una recopilación de métodos y constantes de utilidad y que no van a existir objetos de dichas clases (nunca es necesaria la instanciación). Todos los elementos son "static" y se accede a ellos a través de la clase. P.ej:

1-   x=Math.sqrt(y)

Math y StrictMath son dos clases muy similares. De hecho muchas de las funciones de Math se limitan a llamar a la correspondiente de StrictMath. Cuando existe la diferencia la función de Math es una implementación más eficaz computacionalmente a costa de no ser estrictamente repetible bit a bit, es decir, no puede asegurarse que el resultado sea exactamente el mismo hasta el último bit en diferentes situaciones (máquinas, sistemas operativos, etc). Por el contrario StrictMath nos asegura esto último a costa de una ejecución mas "pesada".

Antes de pasar al siguiente apartado es preciso mencionar el hecho de que existe un paquete denominado java.math que no debe ser confundido con las clases que acabamos de ver. Este paquete incluye clases con representaciones de tipos de datos para llevar a cabo aritmética de precisión indefinida.

(6) La clase Trowable

En el paquete que nos ocupa se encuentra también la raíz de todas las clases de error y excepción: la clase Throwable. Como ya se vió en el capítulo dedicado a errores y excepciones, esta clase es muy sencilla y lo más común es que sus descendientes no añadan nada nuevo, limitandose su funcionalidad a ser una clase diferenciada de otras y asociarse de este modo a un tipo concreto de error o excepción. Cada paquete de la biblioteca contiene un conjunto de clases de error y de excepción que le son propias.

(7) Otras clases

Otras clases que pertenecen a este paquete son dedicadas a seguridad (SecurityManager), generación y control de procesos e hilos para ejecución paralela (Process, Thread y otras), carga explícita de clases (ClassLoader), compilación Compiler), cuestiones relacionadas con la ejecución (Runtime), etc.

Una vez visto todo lo anterior, puede ser una buena idea dedicar un rato a revisar el paquete java.lang.

Siguiente punto: 6.3- Clases de utilidad (java.util) /iterator/


Plataforma de soporte a curso y contenidos (c) German Bordel 2005.