何时使用包装类和基本数据类型?

119

什么情况下我应该选择包装类(wrapper class)而不是基本类型(primitive types)?或者在什么情况下我应该在包装类和基本类型之间进行选择?


2
这篇文章可能有助于本次讨论。请参阅:http://www.w3resource.com/java-tutorial/java-wrapper-classes.php - pankaj
11个回答

75

有人提到某些构造如Collections需要对象,而对象比原始类型(内存和装箱)更耗费资源。

另一个考虑因素是:

初始化对象为null或将null参数传递给方法/构造函数以表示状态或功能非常方便,但无法用原始类型实现。

许多程序员将数字初始化为0(默认值)或-1来表示这一点,但取决于情况,这可能是不正确或具有误导性的。

这也会为之后出现的一些错误设置了舞台,例如NullPointerException,这比在代码中随意出现的其他错误更加友好。


19
将对象初始化为null可能很方便,但这是不正确的做法。如果该字段是可选的,应显式地指明这一点。 - Eddie Jamsession
13
谢谢 @EddieJamsession,我再也不会将其初始化为 null 了。 (噗) - pstanton
1
@EddieJamsession 如果将对象初始化为null作为指示设置实际值失败的方法失败了,您还有什么其他建议来解决这个问题?哦,我刚刚意识到:异常。NullPointerException太泛泛了;最好使用非常具体的自定义异常来指示出错的原因。好的,从现在开始我会这样做... - klaar
1
@EddieJamsession 在阅读相关资料后,我了解到了 Optional 对象的概念。没错。 - klaar
@klaar 什么是可选对象? - carloswm85
@carloswm85 一个 java.util.Optional<T> 对象是一个包装器,它能够区分值或对象的存在和不存在。它的设计使您不必使用某个实际值作为缺少值的占位符。值 NULL 经常用作这样的占位符,但它不会强制您考虑异常情况(当您粗心时导致 NullPointerExceptions),而 Optional 则需要,因为您必须考虑当包装器为空时要做什么。 - klaar

23

通常情况下,应该使用基本数据类型,除非出于某些原因需要对象(例如放进集合中)。即使如此,如果你想最大化数值性能,请考虑一个不需要对象的不同方法。这是由文档建议的,而这篇文章展示了自动装箱可能导致很大的性能差异。


3
代码的易读性和可靠性不应该被牺牲,因为性能损失并不是那么严重。 - pstanton
3
首先,恰当地使用原语不会使您的代码难以理解。其次,在某些情况下,性能影响是显著的。说从未有过性能影响是荒谬的。 - Matthew Flaschen
1
@pstanton:请解释一下Integerint更易读的原因。 - Stephen C
性能是基于应用程序的本质而占据首要位置。一般来说,如果是一个 Web 应用程序,毫秒不会很重要,但如果是桌面应用程序,则有意义的是不要直接从用户面前减去那额外的一秒钟。 - Pradeep
绝对动画是一个典型的需要严格使用基本数据类型的例子,因为变量在高频率下不断变化。我认为一个合格的程序员应该能够识别这种情况。 - pstanton
显示剩余3条评论

17
在我看来,如果我的类成员是包装变量,那么它不依赖于默认值,这是开发人员友好的行为。
class Person {
   int SSN ; // gets initialized to zero by default 
}

2.

class PersonBetter {
  Integer SSN; //gets initialized to null by default
}

在第一种情况下,您不能保持SSN值未初始化。如果在尝试使用它之前没有检查该值是否已设置,则可能会受到伤害。
在第二种情况下,您可以将SSN初始化为null。这可能会导致NullPointerException,但比在未初始化SSN字段的情况下无意中将默认值(零)插入数据库要好。

4
建造者模式旨在解决这个问题。在这种情况下,您可以创建一个名为 PersonBuilder 的类,在调用“build”以获取 Person 实例之前,如果没有设置社会安全号码,则会抛出异常。我认为这样做有些过度,但这是Java语言推广正确设计模式的方式。 - Sandy Chapman

9

如果没有必要,我只会使用包装类型。

使用它们并没有太多好处,除了它们是Objects之外。

而且,你会失去内存使用和时间开销上的开销。


5
你可能不会获得很多,但也不会失去太多。除非你还在使用1990年代的手掌电脑。 - pstanton
它们作为对象的事实也使它们比作为简单原始类型具有更多的上下文和封装性。因此,根据这些原始类型的用途和使用位置,您可能会获得很多好处。 - aberrant80

4
实际上,我遇到了一种情况,可以解释使用包装类的情况。
我创建了一个服务类,其中有一个long类型的变量。
如果变量是long类型,则在未初始化时,它将被设置为0,这将使用户在GUI中显示时感到困惑。
如果变量是Long类型,则在未初始化时,它将被设置为null,这个null值不会显示在GUI中。
这也适用于Boolean,其中当我们使用原始的boolean时,值可能更加令人困惑(因为默认值为false)。

3

对于由数字计算主导的应用程序,使用原始类型可以极大地提高性能。

对于原始类型,使用==运算符,但对于包装器,最好调用equals()方法。

“原始类型被认为是有害的”,因为它们将“过程语义混入一个否则统一的面向对象模型中。”

许多程序员将数字初始化为0(默认)或-1以表示这一点,但根据情况,这可能是不正确或误导性的。


3

集合是简单Java包装对象的典型情况。然而,您可能会考虑在代码中给Wrapper一个更具体的含义(值对象)。

在我看来,几乎总是有利于使用值对象,因为这有助于提高代码的可读性和可维护性。当简单数据结构需要承担某些职责时,将其包装在对象内通常可以简化代码。这在领域驱动设计中非常重要。

当然,还存在性能问题,但我倾向于忽略它,直到我有可能使用适当的数据测量性能并对有问题的区域采取更有针对性的行动。如果代码易于理解,也可能更容易理解性能问题。


1

如果你想使用集合,你必须使用包装类。

原始类型用于数组。此外,用于表示没有行为的数据,例如计数器或布尔条件。

自动装箱后,“何时使用原始类型或包装类”这个界限变得相当模糊。

但请记住,包装器是对象,因此您可以获得所有花哨的Java功能。例如,您可以使用反射创建Integer对象,但不能创建int值。包装类还具有诸如valueOf之类的方法。


除了集合,我不应该使用包装类?那普通声明像 Integer i = new Integer(10); 这样使用呢?这样做好吗? - Gopi
自动装箱允许你这样做: Integer i = 10; - Tom
1
不,如果您没有要求它是一个对象,请不要把它变成一个对象。 - Matthew Flaschen
自动装箱将解包上述声明的 i,得到 int i=10 还是 Integer i=10? - Gopi
3
int pi = new Integer(10);可以运行。 Integer oi = 10;可以运行。int ni = null;不可以运行。 赋值语句左侧将被转换为右侧所需的类型。 - pstanton

1

何时使用原始类型

  • 在进行大量计算时,原始类型总是更快的——它们具有更少的开销。
  • 当您不希望变量能够为null时。
  • 当您不希望默认值为null时。
  • 如果方法必须返回一个值。

何时使用包装类

  • 当您使用集合或泛型时——它是必需的。
  • 如果您想要类型的MIN_SIZE或MAX_SIZE。
  • 当您希望变量能够为null时。
  • 当您希望默认值为null时。
  • 如果有时方法可以返回null值。

来自https://medium.com/@bpnorlander/java-understanding-primitive-types-and-wrapper-objects-a6798fb2afe9


0

Java中的原始值不是对象。为了将这些值作为对象进行操作,java.lang包为每种原始数据类型提供了一个包装类。

所有包装类都是final的。可以初始化所有包装类的对象都是不可变的,这意味着包装对象中的值不能被更改。

虽然void类被认为是一个包装类,但它不包装任何原始值,也不能被初始化。它没有公共构造函数,只表示代表关键字void的类对象。


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