【问题标题】:Differences between new Integer(123), Integer.valueOf(123) and just 123new Integer(123)、Integer.valueOf(123) 和 just 123 之间的区别
【发布时间】:2012-01-27 08:49:02
【问题描述】:

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

myMethod(new Integer(123));

我目前正在重构一些代码,Sonar 工具中有一个提示,使用这样的东西对内存更友好:

myMethod(Integer.valueOf(123));

但是在这种情况下,我认为如果我会使用没有区别:

myMethod(123);

我可以理解,如果我将变量传递给方法,但硬编码 int?或者如果会有 Long/Double 等,我想要 Long 表示数字。但是整数?

【问题讨论】:

  • 实际上,您是否使用myMethod(Integer.valueOf(123))myMethod(123) 并不重要,因为自动装箱将为您使用Integer.valueOf()。自己判断哪个更具可读性。 (假设myMethod 接受Integer
  • 从 JDK 9 开始,强烈建议使用 .valueOf() 方法而不是使用构造函数。这是因为它们都有 @HotSpotIntrinsicCandidate 注释,通知 HotSpot VM 它可以使用优化的汇编级代码来获得更好的性能。 --- 如果 HotSpot VM 用手写 * 汇编和/或手写编译器 IR(编译器内在)替换带注释的方法以提高 * 性能,则方法 * 被内在化。

标签: java integer new-operator value-of


【解决方案1】:

new Integer(123) 将为每个调用创建一个新的Object 实例。

根据javadocInteger.valueOf(123) 的不同之处在于它缓存对象...因此,如果您多次调用它,您可能(或可能不会)最终得到相同的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的AutoBoxing——使用它时,JVM会自动为你调用Integer.valueOf()(因此也使用缓存)。

【讨论】:

  • 那么自动装箱总是会创建一个新对象吗?或者它也可以利用缓存?如果您将此信息添加到您的帖子中,我认为您的将是最好的答案。
  • @MananShah 它已经存在(:是的 - 自动装箱使用 Integer.valueOf(),所以它确实使用缓存。
  • @Marcelo 如果new Integer(234) 创建了与现有Integer.valueOf(234) 不同的对象,为什么listIntegers.remove(new Integer(234)); 会起作用?
【解决方案2】:

public static Integer valueOf(int i)

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

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

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

这个 valueOf 变体在 JDK 5 中被添加到 Byte、Short、Integer 和 Long 中(自 JDK 1.4 起,它就已经存在于 Boolean 中的普通情况中)。当然,所有这些都是 Java 中的不可变对象。过去如果你需要一个来自 int 的 Integer 对象,你会构造一个新的 Integer。但在 JDK 5+ 中,你真的应该使用 valueOf,因为 Integer 现在缓存 -128 到 127 之间的 Integer 对象,并且每次都可以将相同的 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);
}

参考Why YOU should use Integer.valueOf(int)

编辑

自动装箱和对象创建:

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

原始类型不会比它们对应的包装类型慢,而且可能快很多。 可能会出现一些涉及 ==(比较引用)和 .equals()(比较值)的意外行为。

通常,当原始类型被装箱到包装类型中时,JVM 会分配内存并创建一个新对象。但是对于一些特殊情况,JVM会重用同一个对象。

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

  • 布尔值真假

  • 所有字节值

  • -128 到 127 之间的短值

  • int 值介于 -128 和 127 之间

  • 字符在 \u0000 到 \u007F

  • 范围内

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      您的方法是否需要intInteger

      new Integer(int)Integer.valueOf(int) 都返回 Integer 对象,但应该首选 valueOf,因为它更有效,因为它返回缓存的对象。如果您的方法需要Integer,您应该使用Integer.valueOf

      如果您的方法需要int,您应该使用int(例如123)。

      但是,以这种方式匹配类型并不是绝对必要的,因为autoboxing 会在类型不匹配时自动将int 转换为Integer,反之亦然。这允许您将int 传递给需要Integer 的方法,并将Integer 传递给需要int 的方法。但请注意,自动装箱会带来性能成本。使用自动装箱的最常见示例是,如果您想将基元存储在集合中。

      【讨论】:

        【解决方案5】:

        仅在 -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 对象,并且每次都可以将相同的 Integer(0) 对象返回给您,而不是将对象构造浪费在全新的相同对象上整数对象。

        【讨论】:

          猜你喜欢
          • 2011-02-25
          • 2020-03-26
          • 1970-01-01
          • 2018-05-18
          • 2023-01-04
          • 2014-03-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多