Autoboxing en Java5

En un post reciente en Java Lobby (http://www.javalobby.org), destapaban algo a tener en cuenta cuando usamos alegremente el autoboxing de Java5.

Para el que no lo sepa, gracias al autoboxing podemos de forma muy sencilla asignar un tipo primitivo a su Wrapper class, y viceversa. Es decir, podemos, por ejemplo, asignar un boolean a una clase Boolean.
Por ejemplo, hasta Java5 hay que hacer:


//Sin autoboxing
boolean pBool=false;
Boolean wBool=new Boolean(pBool);//boxing
boolean pBool2=wBool.booleanValue();//unboxing

Desde Java5, sin embargo, la cosa se simplifica:


//Con autoboxing
boolean pBool=false;
Boolean wBool=pBool;//autoboxing
boolean pBool2=wBool;//autounboxing

Tremenda simplificacion! …en el codigo. Obviamente esto puede tener consecuencias en el rendimiento de la aplicacion, especialmente si mezclamos tipos primitivos y objetos wrapper en exprensiones aritmeticas…. asi lo advierte Sun en su documentacion. Asi que cuidadin, que hay que usar el autoboxing con precauciones.

Pero ojo!!!, porque las precauciones que debemos tomar van mas alla de las que Sun advierte…
Cual creeis que sera el resultado de la ejecucion del siguiente codigo:

package test.absurdo; 

public class TestAbsurdo {

 /**
 * @param args
 */
 public static void main(String[] args) {
	Integer a = 1, b = 1 ;
	Integer c = 130, d = 130 ;

	System.out.println( a == 1 ) ; // A
	System.out.println( a == b ) ; // B
	System.out.println( c == 130 ) ; // C
	System.out.println( c == d ) ; // D
 }
}

  1. false
    false
    false
    false
  2. true
    true
    true
    true
  3. true
    false
    true
    false
  4. true
    true
    true
    false

Si a mi me ponen esto en un examen de certificacion, yo diria que c)
Pero, si lo ejecutamos veremos que la correcta es la d)

Por que???

Desde luego no parece tener sentido que a==b sea true y c==d sea false.

Bien, parece ser que hay una “optimizacion” no documentada, que provoca que cualquier objeto Integer cuyo valor int se encuentre entre -127 y 127, es ‘cacheado’ como si fuese un int. Es por eso que a==b vale true aunque se trate de objetos distintos, porque son ‘cacheados’ como tipos primitivos.

 Ciertamente, uno no usa mucho ‘==’ para comparar objetos, pero conviene tener estas cosas por ahi en la recamara por si algun dia nos encontramos con un corpontamiento ‘esoterico’ de nuestro codigo…

Comentarios

  1. Desde luego, que comportamiento mas extraño, huele a muñonada de los Ingenieros de Sun… o a una optimización un poco rara.
    Un comportamiento es aún mas extraño..

    
    public class TestAbsurdo {
    
     /**
     * @param args
     */
     public static void main(String[] args) {
    	 	int i=0;
    		Integer a=i;
    		Integer b=i;
    		do{
    			System.out.println("i=" i ":a==b--> " (a==b) " :a==i--->" (a==i));
    			i++ ;
    			a=i;
    			b=i;
    		}while(i<200);
     }
    }
    

    El comportamiento es:

    
    i=0:a==b--> true :a==i--->true
    i=1:a==b--> true :a==i--->true
    i=2:a==b--> true :a==i--->true
    ....( para i<128)...
    i=128:a==b--> false :a==i--->true
    i=129:a==b--> false :a==i--->true
    i=130:a==b--> false :a==i--->true
    i=131:a==b--> false :a==i--->true
    i=132:a==b--> false :a==i--->true
    .... para i>128
    

    ¿Cual es la lógica de este comportamiento?
    ...

    Por resumir un poco y para simplificar el código, básicamente si tenemos que utilizar operaciones aritméticas No utilicemos nunca Wrapper.

  2. Si quieres ver cosas graciosas con autoboxing, prueba lo siguiente:
    Short s = 4;
    Integer i = 4;
    boolean b = false;
    b = (s == i); //Error de compilación
    b = (s >= i); //True
    b = (s.equals(4)); //False
    b = (s == 4); //True

    Explicación:
    La 1º línea compara referencias a objetos distintos.

    La 2º línea realiza el unboxing de ‘s’ e ‘i’ y acaba comparando primitivas.

    La 3º línea, el literal 4 es por definición un “int” por lo que hace el autoboxing a un Integer lo que no es comparable con un Short. Para que funcionase deberíamos escribir algo así:
    b = (s.equals((short)4));

    La 4º línea simplemente realiza un unboxing del Short para compararlo con el int.

  3. @mcalister:

    Impresionante, si esta sale en un examen de certificacion no hay manera de acertar!

    Bueno, la tercera quizas la hubiese acertado…. 🙂

Comments are closed.