什么时候应该使用基元而不是包装对象?

When should I use primitives instead of wrapping objects?

提问人:yanchenko 提问时间:10/27/2008 最后编辑:Communityyanchenko 更新时间:12/26/2017 访问量:11023

问:

实际上,这是一个类似的话题,几乎没有实用价值。 据我了解,基元性能更好,应该在任何地方使用,除了与对象相关的功能(例如 检查)是需要的。右?null

Java 性能 对象 原语

评论


答:

5赞 nkr1pt 10/27/2008 #1

是的,基元比对象快。 从 java 5 开始,您甚至可以混合原语和对象,而无需手动将一个对象转换为另一个对象。 自动装箱机制正好可以解决这个问题。

这意味着,如果将基元放入集合中,编译器将不会抱怨,并将基元隐式转换为对象。

评论

0赞 OJ. 10/27/2008
在什么情况下它们更快?传递引用与传递基元一样快。
1赞 nkr1pt 10/27/2008
以 int 为例。Integer 是包含单个 int 字段的 Object。Integer 比 int 笨重得多。它有点像 Fedex 框来包含 int。
10赞 Cheekysoft 10/27/2008 #2

使用基元时速度更快,因为对象在使用前需要拆箱;因此,VM 需要执行一个额外的步骤。例如,为了对 Integer 执行算术运算,必须先将其转换为 int,然后才能执行算术运算。

在许多业务应用程序中,这可能无关紧要。但是,如果你正在写一些非常笨拙的东西,比如图形转换处理器,你更有可能关心。

1赞 carson 10/27/2008 #3

我想说的是,只有当您分析应用程序并看到自动装箱是性能或内存问题时,您才应该担心使用基元而不是包装器。根据我的经验,在谈论基元与包装对象时,内存在 CPU 周期之前成为一个问题。

评论

1赞 alexmcchessers 10/27/2008
我不同意。当您可以首先编写高效的代码时,为什么要等待性能成为问题呢?10 次中有 9 次您不需要包装类提供的额外功能,那么为什么要使用一个呢?
2赞 carson 10/27/2008
10 次中有 9 次您永远不需要优化。大多数时候,您都会从自动装箱功能中受益,否则他们为什么要添加它?当你永远不会注意到时,没有理由让你的生活更难。
1赞 carson 10/27/2008
使代码更具可读性是一个简单的问题。遇到问题时担心性能。
1赞 carson 10/27/2008
约翰,你错过了重点。他们是他们使代码更好的。你到底为什么要说要预先优化代码?使用包装器绝对没有错。
1赞 carson 11/19/2008
你仍然没有抓住重点。如果你从一个整数开始,然后认为“为了提高性能,我应该在这里使用一个int”,那么你已经预先优化了。我没有说到处使用它们,我说在你能证明它是一个问题之前不要担心它。
23赞 VonC 10/27/2008 #4

不要忘记,由于为每个装箱事件创建一个新的包装器是相当昂贵的,特别是考虑到它通常用于方法的单个范围,因此自动装箱使用一个通用包装器池。

这实际上是蝇量级设计模式的实现。当已知值发生装箱时,不会创建新的包装器实例,而是从池中提取并返回预先创建的实例。

一个后果是:仍然不建议使用自动装箱进行科学计算。例如,代码 d = a * b + c 使用 a、b、c 和 d 的整数类,生成的代码为 d.valueOf(a.intValue() * b.intValue() + c.intValue())。所有这些方法调用都有其自身的开销,因此通常建议在需要将基元存储在集合中时使用自动装箱

即便如此,如果您有大量的 Integer 包装 int,开销可能意味着更长的执行时间,最多 20 倍,如本文所述


Jb 补充了以下重要评论:

此外,Wrapper.valueOf(primitive) 使用包装池。所以更喜欢 Integer.valueOf(5) 而不是新的 Integer(5)

评论

0赞 grep 3/9/2015
仍然不建议使用自动装箱进行科学计算?是的,它只是为了性能问题,不是吗?
1赞 VonC 3/9/2015
@grep不确定:我是 6 年多前写的。
1赞 jb. 10/27/2008 #5

如果您需要将基元存储在集合中,则可以使用 commons-primitives

我更喜欢使用原语而不是包装器,只有绝对需要包装器的地方是实体类。数据库支持 null,因此实体也应该支持 null。

我曾经做过一个在数据库访问中使用原语(和自制 ORM)的项目:

 class Foo{
    int xxx = -1;
 ...
 }

然后你有:

 void persist(Foo foo){
     ...
     statement.setInt(15,foo.getXXX()==-1?null:foo.getXXX());
     ...
}

天哪,这是邪恶的。