Java 为什么要在布尔类和类似的不可变类上使用公共构造函数?

Java 为什么要在布尔类和类似的不可变类上使用公共构造函数?,java,constructor,immutability,Java,Constructor,Immutability,(出于这个问题的目的,我们假设有人故意不使用自动(un)装箱,或者是因为有人在编写Java 1.5之前的代码,或者是因为有人觉得自动取消装箱太容易创建NullPointerExceptions。) 以布尔值为例。Boolean(Boolean)构造函数的文档说明: 注意:很少使用此构造函数。除非有新的 实例,静态工厂valueOf(boolean)通常为 更好的选择。它可能会产生明显更好的空间和时间 表演 我的问题是,为什么你一开始就想得到一个新的实例?如果像这样的构造函数是私有的,事情似乎会更

(出于这个问题的目的,我们假设有人故意不使用自动(un)装箱,或者是因为有人在编写Java 1.5之前的代码,或者是因为有人觉得自动取消装箱太容易创建
NullPointerException
s。)

以布尔值为例。
Boolean(Boolean)
构造函数的文档说明:

注意:很少使用此构造函数。除非有新的 实例,静态工厂
valueOf(boolean)
通常为 更好的选择。它可能会产生明显更好的空间和时间 表演

我的问题是,为什么你一开始就想得到一个新的实例?如果像这样的构造函数是私有的,事情似乎会更简单。例如,如果它们是,您可以编写此代码而不存在任何危险(即使
myBoolean
null
):

这是安全的,因为所有true
Boolean
都是对
Boolean.true
的引用,所有false
Boolean
都是对
Boolean.false的引用。但由于构造函数是公共的,可能有人使用过它们,这意味着您必须编写以下内容:

if (Boolean.TRUE.equals(myBoolean))
但真正糟糕的是当你想检查两个布尔值是否相等时。大概是这样的:

if (myBooleanA == myBooleanB)
…变成这样:

if (
    myBooleanA == myBooleanB ||
    (myBooleanA != null && myBooleanA.equals(myBooleanB))
)
更新:随着Java 7的发布,Java.util.Objects使这种更简单的构造成为可能:

if (Objects.equals(myBooleanA, myBooleanB))

我想不出有任何理由要有这些对象的单独实例,这比不必做上面的废话更令人信服。你说呢?

缓存的值永远不会被垃圾收集,因此,只要你想将它们用作软/弱引用,就可以使用构造函数,这样无论何时需要,都可以对其进行垃圾收集。这同样适用于
Long#valueOf()
Integer#valueOf()
,并与可缓存范围内的值关联

在Eclipse中进行引用搜索时,我了解到,在每个
java.lang.Thread
使用
new Boolean()
作为基于软引用的缓存下,甚至会显式地对其进行注释(在
iscloverridden()
方法中):


这些对象类型是必需的,因为集合类只接受对象,因此不能使用本机类型

这引入了您正在谈论的设计缺陷,因此引入了自动装箱

编辑

构造函数是公共的,因为它们总是公共的。在使用一些非常糟糕的代码进行自动装箱之前,您需要
newinteger(0)!=新的整数(0)
为true。这是一个比原始设计更大的缺陷,但是因为它是公共界面的一部分,现在他们不想破坏旧代码


我打赌他们现在可能会反对它,大多数人都会接受它,因为自动装箱可以正常工作。

由于向后兼容,构造函数是公共的。valueOf()仅在java 1.4中添加


在您的示例中,使用布尔值作为三态变量(null/TRUE/FALSE)可能是个坏主意——最好使用枚举(UNKNOWN、TRUE、FALSE),或者如果null不是有效值,请检查它,然后手动取消装箱以测试相等性。

最后一个代码块是错误的。
a==null?b==null:a.equals(b)
a==b | |(a!=null&&a.equals(b))
。或者
对象。eq(a,b)
。您是正确的。我把它改为
a==b | |(a!=null&&a.equals(b))
。关于使用布尔作为三态:我同意,枚举更可取,但这更像是一种防御性编程;i、 e.处理当你只期望是真或假时,有人递给你空值的情况。(这正是我觉得自动取消装箱很危险的原因;当您将对象视为基本体时,很容易忽略null大小写。)
if (Objects.equals(myBooleanA, myBooleanB))
/*
 * Note: only new Boolean instances (i.e., not Boolean.TRUE or
 * Boolean.FALSE) must be used as cache values, otherwise cache
 * entry will pin associated class.
 */