web-dev-qa-db-fra.com

New Integer vs valueOf

J'utilisais Sonar pour rendre mon code plus propre, et il a souligné que j'utilise new Integer(1) au lieu de Integer.valueOf(1). Parce qu'il semble que valueOf n'instancie pas un nouvel objet et est donc plus convivial pour la mémoire. Comment valueOf ne peut-il pas instancier un nouvel objet? Comment ça marche? Est-ce vrai pour tous les nombres entiers?

69
LB40

Integer.valueOf implémente un cache pour les valeurs -128 à +127. Voir le dernier paragraphe de la spécification du langage Java, section 5.1.7, qui explique les exigences de la boxe (généralement implémentées en termes de méthodes .valueOf).

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

71
Brett Kail

Depuis JavaDoc :

public static Integer valueOf (int i) Retourne une instance Integer représentant la valeur int spécifiée. Si une nouvelle instance Integer n'est pas requise, cette méthode doit généralement être utilisée de préférence au constructeur Integer (int), car cette méthode est susceptible de produire des performances d'espace et de temps nettement meilleures en mettant en cache les valeurs fréquemment demandées.

ValueOf est généralement utilisé pour l'autoboxing et donc (lorsqu'il est utilisé pour l'autoboxing) met en cache au moins les valeurs de -128 à 127 pour suivre la spécification d'autoboxing.

Voici l'implémentation valueOf pour Sun JVM 1.5.? Jetez un œil à toute la classe pour voir comment le cache est initialisé.

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);
}
26
pgras

À partir du code source Java.lang.Integer. Le cache entier est configurable. Pour configurer la taille du cache Integer autre que Sun, nous devons utiliser la propriété System Java.lang.Integer.IntegerCache.high selon le code source.

/**
 * 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 et Java.lang.Long crée un cache de 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));
    }
}
2
Dungeon Hunter

ils vous poussent à utiliser valueOf() au lieu de new Integer() donc la méthode valueOf() le fait pour vous, et met en cache la valeur au cas où vous voudriez obtenir le même nombre à l'avenir. Dans ce cas, la méthode n'instanciera pas un nouvel Integer, mais vous donnera celui mis en cache, ce qui rendra la "création" du nouvel Inte beaucoup plus rapide et plus conviviale.

De cette façon, vous pouvez vous poser beaucoup de problèmes si vous êtes inexpérimenté Java programmeur puisque vous conclurez que Integer.valueOf(342)==Integer.valueOf(342), parce que vous pouvez (ou pas) avoir le même pointeur pour deux entiers, et probablement vous le pratiquerez d'une manière, disons, que vous avez appris en C #, donc cela vous montrera de temps en temps, et vous ne saurez pas comment et d'où ils viennent ...

2
ante.sabo