TEORIA DE JAVA

|

HILOS

Un hilo es una secuencia de instrucciones que está controlada por un planificador que se comporta como un flujo de control secuencial. El planificador gestiona el tiempo de ejecución del procesador y asigna de alguna manera dicho tiempo a los diferentes hilos actualmente presentes.
Normalmente los hilos de un proceso (en este contexto el proceso es lo que se suele llamar así en el ámbito de sistemas operativos) suelen tener acceso a todos los recursos disponibles al proceso, es decir, actuan sobre una memoria compartida.


Enumeraciones


En cualquier clase de colección, debe haber una forma de meter cosas y otra de sacarlas; después de todo, la principal finalidad de una colección es almacenar cosas. En un Vector, el método addElement() es la manera en que se colocan objetos dentro de la colección y llamando al método elementAt() es cómo se sacan. Vector es muy flexible, se puede seleccionar cualquier cosa en cualquier momento y seleccionar múltiples elementos utilizando diferentes índices.

Si se quiere empezar a pensar desde un nivel más alto, se presenta un inconveniente: la necesidad de saber el tipo exacto de la colección para utilizarla. Esto no parece que sea malo en principio, pero si se empieza implementando un Vector a la hora de desarrollar el programa, y posteriormente se decide cambiarlo a List, por eficiencia, entonces sí es problemático.

El concepto de enumerador, o iterador, que es su nombre más común en C++ y OOP, puede utilizarse para alcanzar el nivel de abstracción que se necesita en este caso. Es un objeto cuya misión consiste en moverse a través de una secuencia de objetos y seleccionar aquellos objetos adecuados sin que el programador cliente tenga que conocer la estructura de la secuencia . Además, un iterador es normalmente un objeto ligero, lightweight, es decir, que consumen muy pocos recursos, por lo que hay ocasiones en que presentan ciertas restricciones; por ejemplo, algunos iteradores solamente se puede mover en una dirección.

La Enumeration en Java es un ejemplo de un iterador con esas características, y las cosas que se pueden hacer son:

* Crear una colección para manejar una Enumeration utilizando el método elements(). Esta Enumeration estará lista para devolver el primer elemento en la secuencia cuando se llame por primera vez al método nextElement().
* Obtener el siguiente elemento en la secuencia a través del método nextElement().
* Ver si hay más elementos en la secuencia con el método hasMoreElements().

Y esto es todo. No obstante, a pesar de su simplicidad, alberga bastante poder. Para ver cómo funciona, el ejemplo java412.java, es la modificación de anterior, en que se utilizaba el método elementAt() para seleccionar cada uno de los elementos. Ahora se utiliza una enumeración para el mismo propósito, y el único código interesante de este nuevo ejemplo es el cambio de las líneas del ejemplo original

for( int i=0; i < style="font-weight: bold;">Tipos de Colecciones

Con el JDK 1.0 y 1.1 se proporcionaban librerías de colecciones muy básicas, aunque suficientes para la mayoría de los proyectos. En el JDK 1.2 ya se amplía esto y, además, las anteriores colecciones han sufrido un profundo rediseño. A continuación se verán cada una de ellas por separado para dar una idea del potencial que se ha incorporado a Java.

Vector


El Vector es muy simple y fácil de utilizar. Aunque los métodos más habituales en su manipulación son addElement() para insertar elementos en el Vector, elementAt() para recuperarlos y elements() para obtener una Enumeration con el número de elementos del Vector, lo cierto es que hay más métodos, pero no es el momento de relacionarlos todos, así que, al igual que sucede con todas las librerías de Java, se remite al lector a que consulte la documentación electrónica que proporciona Javasoft, para conocer los demás métodos que componen esta clase.

Las colecciones estándar de Java contienen el método toString(), que permite obtener una representación en forma de String de sí mismas, incluyendo los objetos que contienen. Dentro de Vector, por ejemplo, toString() va saltando a través de los elementos del Vector y llama al método toString() para cada uno de esos elementos. En caso, por poner un ejemplo, de querer imprimir la dirección de la clase, parecería lógico referirse a ella simplemente como this (los programadores C++ estarán muy inclinados a esta posibilidad), así que tendríamos el código que muestra el ejemplo java413.java y que se reproduce en las siguientes líneas.

import java.util.*;

public class java413 {
public String toString() {
return( "Direccion del objeto: "+this+"\n" );
}

public static void main( String args[] ) {
Vector v = new Vector();

for( int i=0; i < style="font-weight: bold;">BitSet

Se llama así lo que en realidad es un Vector de bits. Lo que ocurre es que está optimizado para uso de bits. Bueno, optimizado en cuanto a tamaño, porque en lo que respecta al tiempo de acceso a los elementos, es bastante más lento que el acceso a un array de elementos del mismo tipo básico.

Además, el tamaño mínimo de un BitSet es de 64 bits. Es decir, que si se está almacenando cualquier otra cosa menor, por ejemplo de 8 bits, se estará desperdiciando espacio.

En un Vector normal, la colección se expande cuando se añaden más elementos. En el BitSet ocurre los mismo pero ordenadamente. El ejemplo java414.java, muestra el uso de esta colección.

Se utiliza el generador de números aleatorios para obtener un byte, un short y un int, que son convertidos a su patrón de bits e incorporados al BitSet.

Stack


Un Stack es una Pila, o una colección de tipo LIFO (last-in, first-out). Es decir, lo último que se coloque en la pila será lo primero que se saque. Como en todas las colecciones de Java, los elementos que se introducen y sacan de la pila son Object, así que hay que tener cuidado con el moldeo a la hora de sacar alguno de ellos.

Los diseñadores de Java, en vez de utilizar un Vector como bloque para crear un Stack, han hecho que Stack derive directamente de Vector, así que tiene todas las características de un Vector más alguna otra propia ya del Stack. El ejemplo siguiente, java415.java, es una demostración muy simple del uso de una Pila que consisten en leer cada una de las líneas de un array y colocarlas en un String.

Cada línea en el array diasSemana se inserta en el Stack con push() y posteriormente se retira con pop(). Para ilustrar una afirmación anterior, también se utilizan métodos propios de Vector sobre el Stack. Esto es posible ya que en virtud de la herencia un Stack es un Vector, así que todas las operaciones que se realicen sobre un Vector también se podrán realizar sobre un Stack, como por ejemplo, elementAt().

Hashtable

Un Vector permite selecciones desde una colección de objetos utilizando un número, luego parece lógico pensar que hay números asociados a los objetos. Bien, entonces ¿qué es lo que sucede cuando se realizan selecciones utilizando otros criterios? Un Stack podría servir de ejemplo: su criterio de selección es "lo último que se haya colocado en el Stack". Si rizamos la idea de "selección desde una secuencia", nos encontramos con un mapa, un diccionario o un array asociativo. Conceptualmente, todo parece ser un vector, pero en lugar de acceder a los objetos a través de un número, en realidad se utiliza otro objeto. Esto nos lleva a utilizar claves y al procesado de claves en el programa. Este concepto se expresa en Java a través de la clase abstracta Dictionary. El interfaz para esta clase es muy simple:

* size(), indica cuántos elementos contiene,
* isEmpty(), es true si no hay ningún elemento,
* put( Object clave,Object valor), añade un valor y lo asocia con una clave
* get( Object clave ), obtiene el valor que corresponde a la clave que se indica
* remove( Object clave ), elimina el par clave-valor de la lista
* keys(), genera una Enumeration de todas las claves de la lista
* elements(), genera una Enumeration de todos los valores de la lista

Todo es lo que corresponde a un Diccionario (Dictionary), que no es excesivamente difícil de implementar. El ejemplo java416.java es una aproximación muy simple que utiliza dos Vectores, uno para las claves y otro para los valores que corresponden a esas claves.

import java.util.*;

public class java416 extends Dictionary {
private Vector claves = new Vector();
private Vector valores = new Vector();
public int size() {
return( claves.size() );
}
public boolean isEmpty() {
return( claves.isEmpty() );
}

public Object put( Object clave,Object valor ) {
claves.addElement( clave );
valores.addElement( valor );
return( clave );
}

public Object get( Object clave ) {
int indice = claves.indexOf( clave );
// El metodo indexOf() devuelve -1 si no encuentra la clave que se
// esta buscando
if( indice == -1 )
return( null );
return( valores.elementAt( indice ) );
}

public Object remove(Object clave) {
int indice = claves.indexOf( clave );

if( indice == -1 )
return( null );
claves.removeElementAt( indice );
Object valorRetorno = valores.elementAt( indice );
valores.removeElementAt( indice );
return( valorRetorno );
}

public Enumeration keys() {
return( claves.elements() );
}

public Enumeration elements() {
return( valores.elements() );
}

// Ahora es cuando se prueba el ejemplo
public static void main( String args[] ) {
java416 ej = new java416();
for( char c='a'; c <= 'z'; c++ ) ej.put( String.valueOf( c ),String.valueOf( c ).toUpperCase() ); char[] vocales = { 'a','e','i','o','u' }; for( int i=0; i < 19="526," 18="533," 17="460," 16="513," 15="521," 14="495," 13="512," 12="483," 11="488," 10="487," 9="514," 8="523," 7="497," 6="487," 5="489," 3="509," 2="503," 1="475," 0="505}" numero =" n;" numero ="="" oscuridad =" Math.random()"> 0.5;

public String toString() {
if( oscuridad )
return( "Seis semanas mas de Invierno!" );
else
return( "Entrando en la Primavera!" );
}
}

public class java419 {
public static void main(String args[]) {
Hashtable ht = new Hashtable();

for( int i=0; i < 10; i++ )
ht.put( new Oso2( i ),new Prediccion() );
System.out.println( "ht = "+ht+"\n" );

System.out.println( "Comprobando la prediccion para el oso #3:");
Oso2 oso = new Oso2( 3 );
if( ht.containsKey( oso ) )
System.out.println( (Prediccion)ht.get( oso ) );
}
}

El método hashCode() devuelve el número que corresponde a un Oso como un identificador, siendo el programador el responsable de que no haya dos números iguales. El método hashCode() no es necesario que devuelva un identificador, sino que eso es necesario porque equals() debe ser capaz de determinar estrictamente cuando dos objetos son equivalentes.

El método equals() realiza dos comprobaciones adicionales, una para comprobar si el objeto es null, y, en caso de que no lo sea, comprobar que sea una instancia de Oso, para poder realizar las comparaciones, que se basan en los números asignados a cada objeto Oso. Cuando se ejecuta este nuevo programa, sí se produce la salida correcta. Hay muchas clases de la librería de Java que sobreescriben los métodos hashCode() y equals() basándose en el tipo de objetos que son capaces de crear.

Las tablas Hash son utilizadas también por muchas clases de la librería estándar de Java, por ejemplo, para obtener las propiedades del sistema se usa la clase Properties que hereda directamente de Hashtable. Y además, contiene una segunda Hashtable en donde guarda las propiedades del sistema que se usan por defecto.

0 comentarios:

Publicar un comentario