何时使用包装类和原始类型

Posted

技术标签:

【中文标题】何时使用包装类和原始类型【英文标题】:When to use wrapper class and primitive type 【发布时间】:2010-12-06 22:12:09 【问题描述】:

我什么时候应该使用原始类型的包装类?或者在什么情况下我应该在包装器/原始类型之间进行选择?

【问题讨论】:

w3resource.com/java-tutorial/java-wrapper-classes.php这篇文章将有助于讨论。 【参考方案1】:

何时使用原始类型 在进行大量计算时,原始类型总是更快—— 他们的开销要少得多。

When you don’t want the variable to be able to be null.

When you don’t want the default value to be null.

If the method must return a value

何时使用包装类

当您使用集合或泛型时——这是必需的

如果你想要一个类型的 MIN_SIZE 或 MAX_SIZE。

当您希望变量能够为空时。

当您希望默认值为 null 时。

如果有时该方法可以返回空值。

【讨论】:

【参考方案2】:

何时使用原始类型

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

何时使用包装类

当您使用集合或泛型时 - 这是必需的 如果您想要某个类型的 MIN_SIZE 或 MAX_SIZE。 当您希望变量能够为空时。 当您希望默认值为空时。 如果有时该方法可以返回空值。

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

【讨论】:

【参考方案3】:

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

所有 Wrapper 类都是最终的。所有可以启动的包装类的对象都是不可变的,这意味着包装对象中的值不能改变。

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

【讨论】:

【参考方案4】:

其他人提到某些构造(例如 Collections)需要对象,并且对象比其原始对应物(内存和装箱)具有更多开销。

另一个考虑因素是:

将 Objects 初始化为 null 或将 null 参数发送到方法/构造函数以指示状态或功能会很方便。原语无法做到这一点。

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

当某些东西使用不正确时,这也会为NullPointerException 设置场景,这比一些任意错误更适合程序员。

【讨论】:

“将对象初始化为空会很方便”。它不方便,因为这是不正确的,如果该字段是可选的,您应该明确指出这一点。 大声笑@EddieJamsession 谢谢,我永远不会再初始化为null。 (噗噗) @EddieJamsession 如果将 Objects 初始化为 null 作为在设置实际值失败时指示失败的一种方式,您还打算如何解决这个问题?哦,当我输入这个时我才意识到:异常。 NullPointerException 太通用了;最好使用非常具体的自定义异常来指示出了什么问题。好,从现在开始我会这样做...... @EddieJamsession 在阅读了这件事之后,我遇到了 Optional 对象的概念。对。 @klaar 什么是可选对象?【参考方案5】:

实际上,我遇到过可以解释使用包装类的情况。

我创建了一个具有long 类型变量的服务类

    如果变量的类型为long - 未初始化时,它将被设置为 0 - 这在 GUI 中显示时会让用户感到困惑 如果变量的类型为 Long - 未初始化时,它将设置为 null - 此空值不会显示在 GUI 中。

这也适用于Boolean,当我们使用原始boolean(因为默认值为false)时,值可能会更加混乱。

【讨论】:

【参考方案6】:

性能以数值计算为主的应用程序可以从使用原语中获益良多。

原始类型,一种使用 == 运算符,但对于包装器,首选方法是调用 equals() 方法。

"Primitive types considered harmful" 因为它们将“过程语义”混合到一个统一的面向对象模型中。

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

【讨论】:

【参考方案7】:

在我看来,如果我的类成员是包装变量,它不依赖默认值,这是开发人员友好的行为。

1.

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 字段的情况下尝试使用默认值(零)作为 SSN 插入到数据库中要好。

【讨论】:

构建器模式旨在解决这个问题。在这种情况下,如果在调用“build”以获取 Person 实例之前未设置 SSN,您将创建一个 PersonBuilder 引发异常。我认为这种事情太过分了,但这是 Java 语言为了正确的模式而提倡的。【参考方案8】:

集合是简单 Java 包装对象的典型案例。但是,您可以考虑在代码(值对象)中赋予 Wrapper 更具体的含义。

恕我直言,当归结为代码的可读性和可维护性时,使用值对象几乎总是有好处的。当对象具有某些职责时,将简单的数据结构包装在对象内部通常可以简化代码。这在Domain-Driven Design 中非常重要。

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

【讨论】:

【参考方案9】:

通常,您应该使用原始类型,除非您出于某种原因需要一个对象(例如,放入一个集合中)。即使这样,如果您想最大化数值性能,请考虑一种不需要对象的不同方法。 the documentation 建议这样做,this article 演示了自动装箱如何导致巨大的性能差异。

【讨论】:

性能影响不大,代码易读性/可靠性应该退居二线。 首先,适当地使用原语不会使您的代码难以辨认。其次,在某些情况下对性能的影响很大。说它永远不会是荒谬的。 @pstanton:请解释一下Integerint 更易读的原因。 在许多情况下,整数并不比 int 更易读,在这些情况下,我将始终使用 int,或者如果我知道某个变量永远不会为空,我将使用 int,因为 int 和你一样'已经指出稍微更有效率。但是,在许多情况下,其他程序员在使用对象时更容易理解变量的状态,因为可以将其初始化为 null 以表示它尚未准备好。例如,如果您有一个未保存的数据库记录,它具有唯一的递增数字 id,那么在为其分配有效 id 之前,该 id 应该是 0、-1 还是 null?在这种情况下,对象更好。 关于性能 - 在特殊情况下,性能损失可能很大,即如果您正在非常快速地创建大量这些对象,或者如果它们中的许多对象在一段时间内建立起来。但是,我希望一个体面的程序员能够识别这些特殊情况,或者避免或相应地修改。我从来没有说过它永远不重要,但一般来说,它不是。【参考方案10】:

如果你想使用 Collections,你必须使用 Wrapper 类。

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

自自动装箱以来,“何时使用原始或包装器”边界变得相当模糊。

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

【讨论】:

除了集合,我不应该使用包装类吗?将它用于像 Integer i = new Integer(10); 这样的普通声明怎么样?这样做好不好? 自动装箱允许你做 Integer i = 10; 不,斯里。如果你没有要求我是一个对象,就不要让它成为一个对象。 自动装箱会将上面声明的 i 拆箱为 int i=10 或 Integer i = 10? int pi = new Integer(10);作品。整数 oi = 10;作品。 int ni = null;不起作用。 LHS 被转换为 RHS 需要的任何东西。【参考方案11】:

我只会在必要时使用包装器类型。

除了它们是Objects之外,使用它们并没有什么收获。

而且,您会损失内存使用开销和装箱/拆箱时间。

【讨论】:

你可能收获不多,但你也不会失去太多。除非你在 1990 年代的掌上飞行员上跑步。 它们是对象这一事实也为它们提供了比普通原语更多的上下文和封装。因此,根据这些原语的用途和使用地点,您实际上可能会获得很多收益。【参考方案12】:

如果你想创建一个值类型。类似于 ProductSKU 或 AirportCode。

当原始类型(在我的示例中为字符串)定义相等时,您需要覆盖相等。

【讨论】:

仍然有充分的理由包装一个包含字符串作为基对象的值类型。 您的回答没有意义。我不确定你在说什么。不过,我同意您的评论,如果包装类可以提高易读性,那么它们是一个好主意。 值类型或值对象应该被创建并且是不可变的。例如,创建一个“CountryCode”对象是没有意义的: new CountryCode("USA") 然后以相同的方式创建另一个对象,后来它们是不同的。它们只是开始的字符串,但它们背后的意义。通过使用字符串,您可以修改它们(通过附加更多数据等),但它们将不再相等。请参阅这篇文章以更好地描述我要解释的内容:) 我希望这是有道理的 c2.com/cgi/wiki?ValueObject

以上是关于何时使用包装类和原始类型的主要内容,如果未能解决你的问题,请参考以下文章

原始类型包装器

将 Streams 与原始数据类型和相应的包装器一起使用

Java 数据库 ID - 原始类型或包装类型 [重复]

为啥java的一些概念需要使用包装类而不是原始数据类型[重复]

ongl(原始类型和包装类型)

JavaScript - 原始值包装类型