2010-06-04 10 views
64

Estaba usando Sonar para hacer mi código más limpio, y señaló que estoy usando new Integer(1) en lugar de Integer.valueOf(1). Porque parece que valueOf no crea una instancia de un nuevo objeto, por lo que es más amigable con la memoria. ¿Cómo puede valueOf no instanciar un nuevo objeto? ¿Como funciona? Es esto cierto para todos los enteros?Nuevo entero frente a valueOf

+13

Nota: si utiliza autoboxing, utiliza enteros. valueOf (int) para ti. –

Respuesta

66

Integer.valueOf implementa una memoria caché para los valores -128 a +127. Consulte el último párrafo de la Especificación del lenguaje Java, sección 5.1.7, que explica los requisitos para el boxeo (generalmente implementado en términos de los métodos .valueOf).

http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7

+0

lo sé, estaba en algún lugar del desempaquetado, pero pude encontrar la sección. gracias – LB40

+1

Esa sección no dice nada explícito sobre valueOf. El boxeo generalmente se implementa en términos de valueOf, pero eso no es obligatorio. Además, también permite caché de valores fuera de ese rango. Eso es solo un rango mínimo para el boxeo. –

+21

Solo para completar, también tenga en cuenta que en VM Sun, el valor máximo de la memoria caché es configurable por el usuario usando '-XX: AutoBoxCacheMax = ...' –

26

Desde el JavaDoc:

pública estática Entero valueOf (int i) Devuelve una instancia entero que representa el valor entero especificado. Si no se requiere una nueva instancia de Entero, este método generalmente se debe usar con preferencia al Entero del constructor (int), ya que es probable que este método produzca un mejor rendimiento de espacio y tiempo almacenando en caché los valores frecuentemente solicitados.

ValueOf se utiliza generaly para autoboxing y por lo tanto (cuando se utiliza para autoboxing) almacena en caché al menos valores a partir de -128 a 127 a seguir la especificación autoboxing.

Aquí está la implementación valueOf para Sun JVM 1.5.? Echa un vistazo a toda la clase para ver cómo se inicializa el caché.

public static Integer valueOf(int i) { 
    final int offset = 128; 
    if (i >= -128 && i <= 127) { // must cache 
     return IntegerCache.cache[i + offset]; 
    } 
    return new Integer(i); 
} 
2

que están empujando a utilizar en lugar de valueOf()new Integer() lo que el método valueOf() lo hace por usted, y almacena en caché el valor en caso de que desea obtener el mismo número de nuevo en el futuro. En ese caso, el método no instatará el nuevo entero, pero le dará el almacenado en caché, lo que hará que la 'creación' del nuevo entero sea más rápida y el proceso sea más amigable con la memoria.

De esta manera puede causar mucho problemas si eres un programador de Java sin experiencia ya que concluirás que Integer.valueOf(342)==Integer.valueOf(342), porque puedes (o no) tener el mismo puntero para dos enteros, y probablemente lo practiques de una manera, digamos, aprendiste en C#, de modo que le mostrará bugs de vez en cuando, y no sabrá cómo & de donde provienen ...

2

del código fuente de java.lang.Integer. El caché de enteros es configurable. Para configurar el tamaño de caché Integer distinto de Sun, necesitamos utilizar la propiedad del sistema java.lang.Integer.IntegerCache.high según el código fuente.

/** 
* Cache to support the object identity semantics of autoboxing for values between 
* -128 and 127 (inclusive) as required by JLS. 
* 
* The cache is initialized on first usage. During VM initialization the 
* getAndRemoveCacheProperties method may be used to get and remove any system 
* properites that configure the cache size. At this time, the size of the 
* cache may be controlled by the vm option -XX:AutoBoxCacheMax=<size>. 
*/ 

// value of java.lang.Integer.IntegerCache.high property (obtained during VM init) 
private static String integerCacheHighPropValue; 

static void getAndRemoveCacheProperties() { 
    if (!sun.misc.VM.isBooted()) { 
     Properties props = System.getProperties(); 
     integerCacheHighPropValue = 
      (String)props.remove("java.lang.Integer.IntegerCache.high"); 
     if (integerCacheHighPropValue != null) 
      System.setProperties(props); // remove from system props 
    } 
} 

private static class IntegerCache { 
    static final int high; 
    static final Integer cache[]; 

    static { 
     final int low = -128; 

     // high value may be configured by property 
     int h = 127; 
     if (integerCacheHighPropValue != null) { 
      // Use Long.decode here to avoid invoking methods that 
      // require Integer's autoboxing cache to be initialized 
      int i = Long.decode(integerCacheHighPropValue).intValue(); 
      i = Math.max(i, 127); 
      // Maximum array size is Integer.MAX_VALUE 
      h = Math.min(i, Integer.MAX_VALUE - -low); 
     } 
     high = h; 

     cache = new Integer[(high - low) + 1]; 
     int j = low; 
     for(int k = 0; k < cache.length; k++) 
      cache[k] = new Integer(j++); 
    } 

    private IntegerCache() {} 
} 

De java.lang.Short, java.lang.Byte y java.lang.Long crea una caché por 127 -128

private static class LongCache { 
    private LongCache() { 
    } 

    static final Long cache[] = new Long[-(-128) + 127 + 1]; 

    static { 
     for (int i = 0; i < cache.length; i++) 
      cache[i] = new Long(i - 128); 
    } 
} 

private static class ShortCache { 
    private ShortCache() { 
    } 

    static final Short cache[] = new Short[-(-128) + 127 + 1]; 

    static { 
     for (int i = 0; i < cache.length; i++) 
      cache[i] = new Short((short) (i - 128)); 
    } 
} 

private static class ByteCache { 
    private ByteCache() { 
    } 

    static final Byte cache[] = new Byte[-(-128) + 127 + 1]; 

    static { 
     for (int i = 0; i < cache.length; i++) 
      cache[i] = new Byte((byte) (i - 128)); 
    } 
}