new Integer(123), Integer.valueOf(123)和只有123的区别

34

最近我看到了这样的Java代码:

myMethod(new Integer(123));

我目前正在重构一些代码,在Sonar工具中看到了一个提示,建议使用以下代码更加内存友好:

myMethod(Integer.valueOf(123));

然而在这种情况下,我认为如果我使用以下语句是没有区别的:

myMethod(123);

如果我传递变量给方法,我可以理解这一点,但硬编码整数?或者如果有Long/Double等类型,我想要一个数字的Long表示。但是整数呢?


4
如果你执行myMethod(Integer.valueOf(123))或者myMethod(123),实际上并没有区别,因为自动装箱会为你使用Integer.valueOf()。根据可读性自行判断哪种方式更好。(假设myMethod接收的是Integer类型参数) - soulcheck
从JDK 9开始,强烈建议使用.valueOf()方法而不是使用构造函数。这是因为它们都有@HotSpotIntrinsicCandidate注释,通知HotSpot VM可以使用优化的汇编级别代码来获得更好的性能。如果HotSpot VM用手写的汇编和/或手写的编译器IR(编译器内部函数)替换了带注释的方法,则该方法被内置化。 - retromuz
6个回答

41

new Integer(123)每次调用都会创建一个新的Object实例。

根据javadocInteger.valueOf(123)有一个不同之处,它缓存Object,因此如果您调用它多次,可能会(也可能不会)得到相同的Object

例如,以下代码:

   public static void main(String[] args) {

        Integer a = new Integer(1);
        Integer b = new Integer(1);

        System.out.println("a==b? " + (a==b));

        Integer c = Integer.valueOf(1);
        Integer d = Integer.valueOf(1);

        System.out.println("c==d? " + (c==d));

    }

有以下输出:

a==b? false
c==d? true

如果你使用 int 值,那么你就是在使用原始类型(考虑到你的方法签名也使用了原始类型) - 它会使用稍少一点的内存,可能更快,但你无法将其添加到集合中。

此外,如果你的方法签名使用了 Integer,也要看一下 Java 的 自动装箱 - 当你使用它时,JVM 会自动调用 Integer.valueOf() 方法(从而也使用缓存)。


1
自动装箱是否总是创建一个新对象?还是它也可以利用缓存?如果您将此信息添加到您的帖子中,我认为您的答案将是最好的。 - Alex D
1
@MananShah,它已经存在了(: 是的 - 自动装箱使用Integer.valueOf(),因此它确实使用缓存。 - Marcelo
@Marcelo 如果 new Integer(234) 创建了一个与现有的 Integer.valueOf(234) 不同的对象,为什么 listIntegers.remove(new Integer(234)); 会起作用呢? - Treefish Zhang

9

public static Integer valueOf(int i)

返回表示指定 int 值的 Integer 实例。如果不需要新的 Integer 实例,则通常应优先使用此方法而不是构造函数 Integer(int),因为通过缓存经常请求的值,该方法很可能会产生更好的空间和时间性能。

参数:
i - 一个 int 值。
返回:
表示 i 的 Integer 实例。
自从:
1.5

参见http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Integer.html#valueOf%28int%29

JDK 5 中已将此变体添加到 Byte、Short、Integer 和 Long(自 JDK 1.4 起,在 Boolean 的微不足道的情况下已经存在)。这些在 Java 中当然都是不可变对象。过去如果需要从 int 获取 Integer 对象,就需要构造一个新的 Integer。但在 JDK 5+ 中,你应该真正使用 valueOf,因为 Integer 现在会缓存介于-128和127之间的整数对象,并且可以向你返回完全相同的 Integer(0) 对象,而不是浪费对象构造一个全新的相同的 Integer 对象。

private static class IntegerCache {
private IntegerCache(){}

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

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

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

参考为什么您应该使用Integer.valueOf(int)

编辑

自动装箱和对象创建:

我们必须考虑的重要点是,自动装箱不会减少对象创建,但可以减少代码复杂性。一个好的经验法则是,在没有对象需要的情况下使用基本类型,有两个原因:

基本类型不会比它们对应的包装类型更慢,而且可能快得多。 存在一些意外行为,涉及==(比较引用)和.equals()(比较值)。

通常,当基本类型装箱到包装类型时,JVM分配内存并创建新对象。但是对于某些特殊情况,JVM将重用同一对象。

以下是存储为不可变对象的原始类型列表:

  • 布尔值true和false

  • 所有字节值

  • 介于-128和127之间的短值

  • 介于-128和127之间的int值

  • \u0000到\u007F范围内的字符

请参考http://today.java.net/pub/a/today/2005/03/24/autoboxing.html#performance_issue


2

缓存中只实现了-128到+127之间的范围。

Integer a = new Integer(1);
 Integer b = new Integer(1);

 System.out.println("a==b? " + (a==b));

 Integer c = Integer.valueOf(127);
 Integer d = Integer.valueOf(127);

 System.out.println("c==d? " + (c==d)); 

 Integer e = Integer.valueOf(128);
 Integer f = Integer.valueOf(128);

 System.out.println("e==f? " + (e==f)); 

请参考这个Java规范:http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.7
在JDK 5及以上版本中,建议使用valueOf方法。因为Integer现在会缓存从-128到127之间的整数对象,并且可以每次都返回同一个Integer(0)对象,而不是浪费资源构造一个全新的相同的Integer对象。

1

int是原始类型,不是对象。

new Integer(123)Integer.valueOf(123)都返回表示值为123的Integer对象。根据Integer.valueOf()的javadoc:

返回一个表示指定int值的Integer实例。 如果不需要新的Integer实例,则通常应优先使用此方法而不是构造函数Integer(int),因为通过缓存经常请求的值,此方法可能会产生明显更好的空间和时间性能。


1

你的方法需要一个 int 还是一个 Integer

new Integer(int)Integer.valueOf(int) 都返回 Integer 对象,但应该优先使用 valueOf,因为它更高效,可以返回缓存的对象。如果你的方法需要一个 Integer,你应该使用 Integer.valueOf

如果你的方法需要一个 int,你应该使用一个 int(例如:123)。

然而,严格按照类型匹配并不是必须的,因为由于自动装箱的存在,当类型不匹配时会自动将int转换为Integer,反之亦然。这使得您可以将int传递到需要Integer的方法中,将Integer传递到需要int的方法中。但请注意,自动装箱会带来性能开销。使用自动装箱最常见的示例是如果您想要在集合中存储基本类型。


0
当你使用类似 new Integer(88) 的东西时,SpotBugs 代码分析工具会抱怨性能问题。
这个问题的description显示了newvalueOf之间的差异。
方法调用了效率低下的Number构造函数;使用静态的valueOf代替。使用new Integer(int)保证总是会产生一个新对象,而Integer.valueOf(int)允许编译器、类库或JVM缓存值。使用缓存值可以避免对象分配,代码将更快。-128到127之间的值保证具有相应的缓存实例,并且使用valueOf比使用构造函数快大约3.5倍。对于常量范围之外的值,两种样式的性能相同。除非该类必须与Java 5之前的JVM兼容,否则在创建Long、Integer、Short、Character和Byte的实例时,请使用自动装箱或valueOf()方法。Bug类型和模式:Bx - DM_NUMBER_CTOR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接