viernes, 28 de mayo de 2010

numeros constantes y el operador + en java

Al igual que ocurre con las cadenas, el compilador, puede realizar calculos y utilizar el resultado, reemplazando una complicada operacion y minimizando el trabajo en tiempo de ejecucion. Esto resultando en menor uso de memoria y procesador. El ejemplo acontinuacion:

01: package test;
02: 
03: public class NumberConstantTest {
04:         public static void main(String[] args) {
05:                 int a = 1 // number or hours
06:                 * 60 // mins per hour
07:                 * 1000; // milliseconds per second
08:                 float b = (3.5f + 1.2f) / 2f;
09:                 double c = a * (1d / 3d);
10:                 System.out.println(a);
11:                 System.out.println(b);
12:                 System.out.println(c);
13:         }
14: }
15: 

Explicacion
05-07: Un ejemplo de como definir el numero de segundos en una hora (60000), teniendo la posibilidad de definir el numero de horas, cuando sea necesario.
08-08: Realizando una operacion con punto flotante.
09-09: Ejemplo de una combinacion de constantes, con variables.

Compiled from "NumberConstantTest.java"
   public class test.NumberConstantTest extends java.lang.Object{
   public test.NumberConstantTest();
     Code:
      0: aload_0
      1: invokespecial #8; //Method java/lang/Object."<init>":()V
      4: return

   public static void main(java.lang.String[]);
     Code:
      0: ldc #16; //int 60000
      2: istore_1
      3: ldc #17; //float 2.35f
      5: fstore_2
      6: iload_1
      7: i2d
      8: ldc2_w #18; //double 0.3333333333333333d
      11: dmul
      12: dstore_3
      13: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream;
      16: iload_1
      17: invokevirtual #26; //Method java/io/PrintStream.println:(I)V
      20: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream;
      23: fload_2
      24: invokevirtual #32; //Method java/io/PrintStream.println:(F)V
      27: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream;
      30: dload_3
      31: invokevirtual #35; //Method java/io/PrintStream.println:(D)V
      34: return
   }

Explicacion
  • En codigo resultante, despues de ejecutar la decompilacion, utilizando el comando "javap -c" se puede apreciar que el compilador calculo los valores y coloco los resultados donde aplica, sin embargo, cuando se trata de combinaciones de constantes, con variables (incluso siendo constantes), no se optimizas y se realiza la operacion.

miércoles, 26 de mayo de 2010

generics en C#, implementando GetHashCode, Equals y Comparable

A continuacion, la manera de utilizar generics en C#, para implementar las funciones GetHashCode y Equals, asi como la implementacion de IComparable. Este ejemplo es equivalente al ejemplo de java


01: using System;
02: using System.Collections.Generic;
03: 
04: namespace Test
05: {
06:     public abstract class GenericClass<T>
07:     {
08:         internal T id;
09: 
10:         public T Id
11:         {
12:             get
13:             {
14:                 return id;
15:             }
16:             set
17:             {
18:                 id = value;
19:             }
20:         }
21:         public override int GetHashCode()
22:         {
23:             return id.GetHashCode();
24:         }
25:         public override bool Equals(object obj)
26:         {
27:             return this == obj
28:                 || (((object)(id as GenericClass<T>) == null)
29:                     && Equals0((GenericClass<T>)obj));
30:         }
31:         public bool Equals(GenericClass<T> obj)
32:         {
33:             return this == obj || Equals0(obj);
34:         }
35:         private bool Equals0(GenericClass<T> obj)
36:         {
37:             return id.Equals(obj.id);
38:         }
39:     }
40: 
41:     public abstract class GenericClassComparable<T> : GenericClass<T>,
42:         IComparable<GenericClassComparable<T>> where T : IComparable<T>
43:     {
44:         public int CompareTo(GenericClassComparable<T> o)
45:         {
46:             return id.CompareTo(o.id);
47:         }
48:     }
49: }
50: 

Explicacion:
06-06: Declaracion de utilizacion del uso de generics
08-08: Declaracion del id.
10-20: Declaracion de los accesors para el id.
21-24: Definicion de la funcion GetHashCode, empleando las funciones propias del atributo id.
25-38: Definicion de multiples funciones Equals.
41-42: Declaracion del uso de IComparable
44-47: Definicion de la funcion CompareTo

Optimizacion:

viernes, 21 de mayo de 2010

hashCode y equals funcion en Java o GetHashCode y Equals en C#

¿Cual es la relacion de las funciones que obtienen el codigo hash de un objeto, la funcion que determina la igualdad entre 2 objetos?

La respuesta, la dan las tablas de hash o hashtables en ingles. Para explicar el funcionamiento de estas empleare una analogia con los diccionarios (los libros). Un diccionario es un conjunto de palabras con su respectivo significado y las tablas de hash, son un conjunto de llaves asociadas con un valor. Comparando el diccionario con la tabla de hash, las llaves son las palabras y los significados, son los valores.

Para explicar el funcionamiento de la tabla de hash en terminos del diccionario, explicare primero la organizacion de este ultimo.
  1. Las palabras estan ordenadas en orden alfabetico estricto
  2. Las palabras que inician con la misma letra, estan agrupadas bajo esa letra, existiendo un indice de letras (este puede ser un indice o una serie de marcas en la orilla del mismo)
Bajo estas reglas, si yo necesito buscar el significado de la palabra "idioma" primero determino donde estan las palabras que inician con la letra I y posteriormente ubico la palabra dentro de esta seccion. Como nota, si la palabra no esta dentro de esta seccion (palabras que inician con I), no continuo buscando en las palabras que inician con J o H o cualquier otra letra del abecedario (claro, si se como emplear el diccionario).

Comparado con una tabla de hash, el codigo hash se emplea de la misma manera que nosotros empleamos la primer letra de la palabra a buscar en el diccionario, es decir, se emplea, para determinar un rango de busqueda y posteriormente se emplea la funcion que determina igualdad, para determinar la misma. Cabe aclarar que es importante, tanto para la busqueda en el diccionario, como la busqueda en la tabla de hash, que el algoritmo para generar el codigo hash debe ser eficiente (minimizar el tiempo de respuesta), ademas de que dado un valor, siempre debe regresar el mismo codigo.

Con respecto a la funcion equals, se utiliza para saber cual llave del conjunto (o palabra en caso del diccionario) tiene el valor (definicion en el diccionario) que estamos buscando.

Derivado de esto, se observa, que como en la vida real, tanto la funcion para obtener el codigo hash como la funcion para validad la igualdad, deben tener tiempos de respuesta minimos, particularmente la de igualdad, dado que es la que mas se emplea cuando se busca.

Nota: No es mi intencion ahondar en el funcionamiento de las tablas de hash, dado que existen multiples referencias a su funcionamiento en internet e implica conocimiento sobre teoria de colisiones, algunas formulas y conceptos matematicos, estructuras de datos y por supuesto las variantes de cada lenguaje de programacion. En la wikipedia, asi como en las materias relacionadas con estructuras de datos de muchas carreras relacionadas a sistemas se explica ampliamente su funcionamiento e implementacion.

Si lo muesto en este blog, es precisamente por la importancia que tiene definir correctamente las funciones y que ademas, sean eficazes y eficientes (optimas), pues el uso de tablas de hash esta amplamente extendido.

En java existen 2 clases que se emplean ampliamente Hashtable y HashMap. En C# la clase que se emplea normalmente es Hashtable.

Actualmente solo he implementado esta funcionalidad en java, en estas entradas:

Pronto realizare las implementaciones respectivas para C#

operador +=, cadenas, cadenas constante y el compilador en Java

Como se vio en la entrada anterior, el utilizar incorrectamente un operador, puede ser optimizado por el compilador o en su defecto, una instruccion (en apariencia) se puede convertir en un conjunto de instrucciones, que impacta negarivamente en el desempeño del sistema.

El operador += es un ejemplo de operador que nunca se debe utilizar, debido a como esta implementado, veamos este codigo.






1: package test;
2: 
3: public class StringTest {
4:         public static void main(String[] args) {
5:                 String x = "cadena1";
6:                 x += "cadena2";
7:                 System.out.println(x);
8:         }
9: }
10: 

Si de compilamos el codigo java resultante (el archivo .class) con el comando "javap -c", obtenemos lo siguiente:

Compiled from "StringTest.java"
   public class test.StringTest extends java.lang.Object{
   public test.StringTest();
   Code:
   0: aload_0
   1: invokespecial #8; //Method java/lang/Object."<init>":()V
   4: return

   public static void main(java.lang.String[]);
   Code:
   0: ldc #16; //String cadena1
   2: astore_1
   3: new #18; //class java/lang/StringBuilder
   6: dup
   7: aload_1
   8: invokestatic #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   11: invokespecial #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   14: ldc #29; //String cadena2
   16: invokevirtual #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19: invokevirtual #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   22: astore_1
   23: getstatic #39; //Field java/lang/System.out:Ljava/io/PrintStream;
   26: aload_1
   27: invokevirtual #45; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   30: return
   }

El codigo equivalente, para generar el mismo resultado, pero utilizando explicitamente la clase StringBuilder y la funcion valueOf, es el siguiente:

1: package test;
2: 
3: public class StringTest2 {
4:         public static void main(String[] args) {
5:                 String x = "cadena1";
6:                 x = new StringBuilder(String.valueOf(x)).append("cadena2").toString();
7:                 System.out.println(x);
8:         }
9: }
10: 

Pero que ocurre cuando se mete la operacion += dentro de un loop? Como en el siguiente codigo:

01: package test;
02: 
03: public class StringTest3 {
04:         public static void main(String[] args) {
05:                 String x = "cadena1";
06:                 for (int i = 0; i < 10; i++) {
07:                         x += "cadena2";
08:                 }
09:         }
10: }
11: 

Al decompilar, se genera el siguiente codigo:

Compiled from "StringTest3.java"
   public class test.StringTest3 extends java.lang.Object{
   public test.StringTest3();
  Code:
   0: aload_0
   1: invokespecial #8; //Method java/lang/Object."<init>":()V
   4: return

public static void main(java.lang.String[]);
  Code:
   0: ldc #16; //String cadena1
   2: astore_1
   3: iconst_0
   4: istore_2
   5: goto 31
   8: new #18; //class java/lang/StringBuilder
   11: dup
   12: aload_1
   13: invokestatic #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   16: invokespecial #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   19: ldc #29; //String cadena2
   21: invokevirtual #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   24: invokevirtual #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   27: astore_1
   28: iinc 2, 1
   31: iload_2
   32: bipush 10
   34: if_icmplt 8
   37: return

}

Es decir, el codigo equivalente es el siguiente:

01: package test;
02: 
03: public class StringTest4 {
04:         public static void main(String[] args) {
05:                 String x = "cadena1";
06:                 for (int i = 0; i < 10; i++) {
07:                         x = new StringBuilder(String.valueOf(x)).append("cadena2").toString();
08:                 }
09:         }
10: }
11: 

Como se puede observar, en cada iteracion, se construye un nuevo objeto StringBuilder, con el resultado de ejecutar la funcion valueOf, que recibe como parametro la variable x, posterior mente, se agrega la cadena que "cadena2" y finalmente, se convierte en una cadena nueva, la cual se asigna a la variable x.

Derivado de esto es destacable notar que este codigo es ineficiente, en la mayoria de las situaciones, particularmente cuando se emplea dentro de loops.

Sin embargo, cuando se emplea en conjunto con el operador +, puede eficiente, pero solo si se conoce exactamente la cantidad de elemenos implicados en la operacion. Como en el siguiente ejemplo:

01: package test;
02: 
03: public class StringTest5 {
04:         public static void main(String[] args) {
05:                 String x = "cadena1";
06:                 String y = "auxiliar";
07:                 x += "cadena2" + y;
08:                 System.out.println(x);
09:         }
10: }
11: 

Al de compilar se obtiene lo siguiente:

Compiled from "StringTest5.java"
   public class test.StringTest5 extends java.lang.Object{
   public test.StringTest5();
   Code:
   0: aload_0
   1: invokespecial #8; //Method java/lang/Object."<init>":()V
   4: return

public static void main(java.lang.String[]);
   Code:
   0: ldc #16; //String cadena1
   2: astore_1
   3: ldc #18; //String auxiliar
   5: astore_2
   6: new #20; //class java/lang/StringBuilder
   9: dup
   10: aload_1
   11: invokestatic #22; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   14: invokespecial #28; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   17: ldc #31; //String cadena2
   19: invokevirtual #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22: aload_2
   23: invokevirtual #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   26: invokevirtual #37; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   29: astore_1
   30: getstatic #41; //Field java/lang/System.out:Ljava/io/PrintStream;
   33: aload_1
   34: invokevirtual #47; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   37: return
}

El codigo equivalente, es el siguiente:

01: package test;
02: 
03: public class StringTest6 {
04:         public static void main(String[] args) {
05:                 String x = "cadena1";
06:                 String y = "auxiliar";
07:                 x = new StringBuilder(String.valueOf(x)).append("cadena2").append(y)
08:                                 .toString();
09:                 System.out.println(x);
10:         }
11: }
12: 

Lo cual es eficiente para en terminos de uso de los objetos creados.

martes, 18 de mayo de 2010

operador +, cadenas, cadenas constante y el compilador en Java

"Mucho ayuda el que no estorba"

El uso de cadenas, en un sistema es casi inevitable, pues las personas en general leen y escriben cadenas, independientemente de que estas representen fechas, numeros, palabras, etc.

La generacion de estas cadenas, repercute negativamente en el desempeño de una aplicacion o sistema, sobre todo, cuando se generan y utilizan de manera incorrecta o excesiva.

Un ejemplo es el operador + en el lenguaje de programacion, que cuando es correctamente empleado, puede no ser una carga excesiva, pero cuando se emplea incorrectamete o se mal interpreta su utilizacion, puede provocar que se trabaje de manera excesiva, consumiendo tiempo de procesamiento y memoria indiscriminadamente.

La mayoria de los lenguajes compilados, como Java, particularmente, los que no soportan sobrecarga de operadores por programacion, convierten las instrucciones que tienen el operador + cuando estan operando con cadenas, en objetos y/o funciones. Sin embargo, el compilador, puede tener la capacidad de manipular el codigo resultante, para minimizar el uso de los recursos (memoria y procesador)

En el siguiente codigo, se hace uso del operador +.




01: package test;
02: 
03: public class StringTest {
04:         public static void main(String[] args) {
05:                 String a = "cadena1";
06:                 String b = "cadena2";
07:                 String c = a + b;
08:                 System.out.println(c);
09:         }
10: }
11: 

Posteriormente ejecutamos los siguientes comandos:

   javac test\StringBuilderTest.java

   javap -c -classpath . test.StringTest

Obteniendo el siguiente codigo:

Compiled from "StringTest.java"
   public class test.StringTest extends java.lang.Object{
   public test.StringTest();
   Code:
   0: aload_0
   1: invokespecial #8; //Method java/lang/Object."<init>":()V
   4: return

   public static void main(java.lang.String[]);
   Code:
   0: ldc #16; //String cadena1
   2: astore_1
   3: ldc #18; //String cadena2
   5: astore_2
   6: new #20; //class java/lang/StringBuilder
   9: dup
   10: aload_1
   11: invokestatic #22; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   14: invokespecial #28; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   17: aload_2
   18: invokevirtual #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   21: invokevirtual #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   24: astore_3
   25: getstatic #39; //Field java/lang/System.out:Ljava/io/PrintStream;
   28: aload_3
   29: invokevirtual #45; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   32: return
   }

Como se puede observar, el compilador, tradujo la sentencia con el operador + en el uso de la funcion valueOf, la creacion de un objeto StringBuilder, el uso de la funcion append y finalmente toString, es decir algo como esto:



01: package test;
02: 
03: public class StringTest2 {
04:         public static void main(String[] args) {
05:                 String a = "cadena1";
06:                 String b = "cadena2";
07:                 String c = new StringBuilder(String.valueOf(a)).append(b).toString();
08:                 System.out.println(c);
09:         }
10: }
11: 

Nosotros conocemos que se estan empleando constantes, por lo que podemos substituir la variable por el valor.


1: package test;
2: 
3: public class StringTest3 {
4:         public static void main(String[] args) {
5:                 String c = "cadena1" + "cadena2";
6:                 System.out.println(c);
7:         }
8: }
9: 

Ejecutamos la compilacion (javac) y de compilacion (javap), obteniendo lo siguiente:

Compiled from "StringTest3.java"
   public class test.StringTest3 extends java.lang.Object{
   public test.StringTest3();
   Code:
   0: aload_0
   1: invokespecial #8; //Method java/lang/Object."<init>":()V
   4: return

   public static void main(java.lang.String[]);
   Code:
   0: ldc #16; //String cadena1cadena2
   2: astore_1
   3: getstatic #18; //Field java/lang/System.out:Ljava/io/PrintStream;
   6: aload_1
   7: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   10: return
   }

Este es el codigo equivalente, el cual genera el mismo codigo compilado, que el codigo anterior.



1: package test;
2: 
3: public class StringTest4 {
4:         public static void main(String[] args) {
5:                 String c = "cadena1cadena2";
6:                 System.out.println(c);
7:         }
8: }
9: 

Como se puede notar, cuando se utilizan constantes, el operador + y el compilador, pueden optimizar el codigo, siempre y cuando la constante este "inline". De ahi, la frase inicial "mucho ayuda el que no estorba", en ocasiones hay que dejar que el compilador haga su trabajo.

viernes, 14 de mayo de 2010

binario a hexadecimal en C

Funcion que genera una cadena hexadecimal en base a una cadena binaria. Esta funcionalidad es util, para tranportar o almacenar informacion binaria y posteriormente recuperarla





01: #include <stdlib.h>
02: #include <string.h>
03: 
04: static const char *base="0123456789abcdef";
05: 
06: static const unsigned int ibase[]={
07:         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
08:         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
09:         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10:         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11:         0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
12:         2, 3, 4, 5, 6, 7, 8, 9, 0, 0,
13:         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
14:         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
15:         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16:         0, 0, 0, 0, 0, 0, 0, 10, 11, 12,
17:         13, 14, 15};
18: 
19: char *uchar2hex(const unsigned char *in, size_t len)
20: {
21:         char *out;
22:         int i;
23:         int l;
24: 
25:         l=sizeof(char)*len*2+1;
26:         out=malloc(l);
27:         out[l]='\0';
28:         for(i=0;i<len;i++)
29:         {
30:                 int p;
31:                 int t;
32: 
33:                 p=i*2;
34:                 t=in[i];
35:                 out[p]=base[(t>>4)&0x0F];
36:                 out[p+1]=base[t&0x0F];
37:         }
38:         return out;
39: }
40: 
41: unsigned char *hex2uchar(char *hexstr, size_t *len)
42: {
43:         unsigned char *out;
44:         int i;
45:         int l;
46: 
47:         l=strlen(hexstr)/2;
48:         out=malloc(sizeof(unsigned char)*l);
49:         for(i=0;i<l;i++)
50:         {
51:                 int p;
52: 
53:                 p=i*2;
54:                 out[i]=(unsigned char)((ibase[hexstr[p]&0xEF]<<4)|(ibase[hexstr[p+1]&0xEF]&0xFF));
55:         }
56:         *len=l;
57:         return out;
58: }
59: 

Explicacion:

04-04: Caracteres validos en hexadecimal, ordenados convenientemente
06-17: Arreglo que sirve para invertir el proceso, convirtiendo un caracter hexadeximal en binario
19-39: Funcion que codifica la informacion binaria en una cadena hexadecimal, la longitud de la informacion binaria, esta indicada por len.
41-58: Funcion que extrae la informacion binaria de una cadena hexadecimal, la longitud resultante se almacenara en la direccion de len.

Optimizacion:
  • Se construye el arreglo resultante con la logitud exacta necesaria
  • Se emplean arreglos, para minimizar el numero de operaciones
Notas:
  • Los valores regresados por estas funciones, se deben liberar con la funcion free, pues se aloja memoria con malloc 
  • En esta version, solo es posible usar minusculas

miércoles, 12 de mayo de 2010

Extraccion del nombre de una propiedad del getter respectivo en java

Extraccion del nombre de una propiedad del getter respectivo

Esta funcionalidad es requerida, para obtener dinamicamente el nombre de la propiedad asociada al methodo getter, sin embargo, puede complicarse, debido a que el estandard puede aceptar el prefijo is o el prefijo get






01: package test;
02: 
03: public class Test {
04:         public String getProperty(String methodName) {
05:                 assert methodName.startsWith("get") || methodName.startsWith("is");
06:                 int index = methodName.charAt(0) == 'i' ? 2 : 3;// cache
07:                 char c = Character.toLowerCase(methodName.charAt(index));// cache
08:                 int l = methodName.length();
09:                 if ((index == 3 && l > 4) || (index == 2 && l > 3)) {
10:                         return new StringBuilder(l-index).append(c).append(
11:                                         methodName.substring(index + 1)).toString();
12:                 } else {
13:                         return new String(new char[] { c });
14:                 }
15:         }
16: }
17: 

Explicacion:
06-06: Determinar donde inicia el nombre de la propiedad.
07-07: El primer caracter del nombre de la propiedad, lo convertimos a minuscula
09-14: Determinamos si el nombre de la propiedad, esta formado por 1 o mas letras.

Optimizacion:
  • Se realiza cache de variables, como el indice, para evitar calcularlo en cada ocasion
  • Cuando el nombre de la propiedad esta formado por un solo caracter se construye una cadena formada por ese caracter exclusivamente, en caso contrario, se forma la cadena correspondiente.
  • Cuando el nombre de la propiedad esta formado por mas de un caracter, se crea un StringBuilder de longitud exacta.

lunes, 10 de mayo de 2010

como llenar un elemento select de html

En ocasiones al momento de llenar un objeto select, dentro de una forma html. La manera de realizar este llenado, influye mucho en la velocidad de despliegue.




01: function fillSelect(obj_select, arr_data) {
02:         var opts = obj_select.options; //cache, direct access
03:         var l = arr_data.length;//cache
04:         opts.length = l;//resize
05:         for (i = 0; i > l; i++) { //fill
06:                 var opt = opts[i];//cache, direct access
07:                 var d = arr_data[i];//cache
08:                 opt.value = d.value;//value for current option
09:                 opt.text = d.label;//text for current option
10:         }
11: }

Explicacion:
01-01: Declaracion de la funcion fillSelect, la cual recibe el elemento select y el arreglo que contiene los nuevos datos del select.
04-04: Cambio en longitud de los elementos (options) que componen el select.
05-10: Llenado de las opciones a mostrar en el componente select. Sin crear objetos innecesarios.

Optimizacion:
  • Se trata de realizar un acceso directo a las propiedades o atributos de los objetos (lineas 02, 03, 06 y 07), utilizando variables locales en vez de referencias.
  • Se evita la construccion innecesaria de objetos option, dado que al cambiar la longitud del arreglo representado por la propiedad options del elemento select, se crean tantos objetos option, como grande sea este arreglo (linea 04). Derivado de esto, solo se le asignan los valores al iesimo option y no como comun mente se hace, creando un objeto option y asignandolo al iesimo elemento en el arreglo. Esto repercute en un uso minimo de memoria.

sábado, 8 de mayo de 2010

implementando la funcion compareTo de Comparable con Generics en java

En esta ocasion, utilizando el codigo de la entrada anterior utilizando herencia en esta clase, se implementa Comparable, para poder utilizar la funcionalidad de Collections.




01: package test;
02: 
03: public abstract class GenericsBeanComparable<T extends Comparable<T>> extends
04:                 GenericsBean<T> implements Comparable<GenericsBeanComparable<T>> {
05: 
06:         public int compareTo(GenericsBeanComparable o) {
07:                 return this.id.compareTo(o.id);
08:         }
09: 
10: }

Explicacion:
03-04: Se define el tipo que se va a emplear , notese que T es Comparable, dando la posibilidad de utilizar clases como Long, Integer, String, etc.
06-08: Se define como se comparara la unica propiedad que conocemos (id) con el id del otro objeto.

Optimizacion:
  • Como en la clase padre, al implementar esta clase, implicitamente, se puede utilizar la funcionalidad de clases como Collections.sort o Collections.binarySearch. Ademas de implementar la funcionalidad de hashCode y equals, heredadas de la clase padre.

Nota:
  • La funcionalidad por defecto, solo compara la propiedad id, por lo que seria recomendable sobreescribir el metodo, para poder comparar otras propiedades, en caso de ser necesario.
Ejemplo:



01: package test;
02: 
03: public class Person extends GenericsBeanComparable<Integer> {
04: 
05:         private String name;
06:         private Integer age;
07: 
08:         public String getName() {
09:                 return name;
10:         }
11: 
12:         public void setName(String name) {
13:                 this.name = name;
14:         }
15: 
16:         public Integer getAge() {
17:                 return age;
18:         }
19: 
20:         public void setAge(Integer age) {
21:                 this.age = age;
22:         }
23: 
24: }

En este ejemplo se define la clase persona, la cual, tiene definido un id de tipo Integer, junto con las funciones hashCode, equals y CompareTo. definidas anteriormente, pueden crear 2 objetos distintos y determinar si son o no iguales, incluso ingresarlos en una tabla de hash (Hashtable o HashMap). E incluso, si se define una Lista de objetos Person y utilizar las funciones sort y binarySearch de Collections.

    miércoles, 5 de mayo de 2010

    implementando las funciones hashCode y equals con generics en java

    En la entrada anterior, se mostro como implementar la funcion equals y hashCode, utilizando una clase especifica (String), sin embago, es posible implementar la funcionalidad anteriormente descrita, utilizando generics de java, funcionalidad introducida en la version 1.5 (5.0).




    01: package test;
    02: 
    03: public abstract class GenericsBean<T> {
    04: 
    05:         T id;
    06: 
    07:         @Override
    08:         public int hashCode() {
    09:                 return id.hashCode();
    10:         }
    11: 
    12:         @SuppressWarnings("unchecked")
    13:         @Override
    14:         public boolean equals(Object obj) {
    15:                 return this == obj
    16:                                 || (obj instanceof GenericsBean && equals0((GenericsBean<T>) obj));
    17:         }
    18: 
    19:         public boolean equals(GenericsBean other) {
    20:                 return this == other || equals0(other);
    21:         }
    22: 
    23:         protected boolean equals0(GenericsBean other) {
    24:                 return this.id.equals(other.id);
    25:         }
    26: 
    27:         public T getId() {
    28:                 return id;
    29:         }
    30: 
    31:         public void setId(T id) {
    32:                 this.id = id;
    33:         }
    34: 
    35: }
    36: 
    Explicacion:

    03-03: Se define la clase "parametrizada" que se empleara para definir el id del bean. Esta clase del id, puede ser incluso un id compuesto (un bean) y no solo un tipo nativo (Integer, Long, String, etc).
    07-10: Se define el hashCode, utiilzando el hashCode del objeto id. A esta funcion se le agrega la anotacion @SuppressWarnings("unchecked"), para que el compilador no muestre mensajes de alerta debido a la conversion de un tipo "Generico".
    19-21: Definicion de equals, para comparar contra un objeto cualquiera.
    23-25: Definicion de la funcion equals0, la cual utiliza el equals del id.

    Optimizacion:
    1. La utilizacion de este codigo, ayuda a no definir estas funciones en cada ocasion. La mayor desventaja, radica en que no es posible cambiarle el nombre al atributo id.
    Actualizacion:
    • Se suprime el private en el id, para permitir acceso "friend"