为什么整数在Java中是不可变的?
我知道整数在Java中是不可变的。 但为什么这样设计呢?
在提出这个问题之前,我通过了其他答案:
整数是不可改变的
i ++仍在为Java中的不可变Integer工作?
为什么Java包装类是不可变的?
但我找不到强制使用Integer不变的用例。 是否存在类似String的技术原因?
- 字符串在网络连接,数据库URL等中用作参数。如果它是可变的,它很容易被破坏。
- 支持StringPool工具。
- 支持将字符串用作参数的类加载机制。 字符串是可变的导致加载错误的类。
我知道像AtomicInteger
这样的包装器是可变的。
更新:
从谈话中,没有普遍的理由可以强制整数是不可变的。 然而,通过做不可变,它提供了答案中提到的一些奖励。
比如安德烈的这句话
缓存的可能性。
其他人正在减少全球状态
更容易multithreading
您将找不到java.lang
包装器必须是不可变的强制性原因。 仅仅因为这是一个设计决定 。 他们本来可以另有决定。 语言设计者必须在可变和不可变之间做出选择。 他们选择了不变的 。 而已。
尽管有一些令人信服的 (IMO)原因使它们变得不可变 :
它与String
一致。 您为String
提供的不可变的相同推理也适用于Integer
等(例如,考虑属性映射中的端口号)。 这通常适用于任何可变类型 。
不可变类型排除了过多的难以发现的错误,可以通过修改通过getter获得的值来非自愿地改变对象成员值。 当类型不可变时,它可以节省大量的防御性复制 。 最臭名昭着的例子是java.util.Date
,这通常很难使用,因为它是可变的 (除了API问题)。
同样不可变的类型允许使用共享实例,例如Integer
对常用值的使用(参见Integer.valueOf(int)
)。
价值1
的身份能否改变? 可以变成2
吗? 不。这就是为什么Integer
和其他数字类型是不可变的。 他们的目的是模仿这种身份。
为了使对象引用封装一个受持有它的东西控制的值,必须应用以下三个条件之一:
-
对象的类必须是不可变的。
-
引用必须标识一个永远不会暴露于任何可能使其变异的实例。
-
绝不能与任何不受其持有者控制的对象共享引用,无论这样的东西是否会改变它。
保存Integer
类型引用的代码通常是为了封装整数值。 使Integer
不可变使得类可以自由地共享用于封装值的引用。 虽然有时候MutableInteger
类本身有用[这样的东西可能比单元素int[]
更清晰一点且比AtomicInteger
更有效],但是不会将MutableInteger
类传递给方法传递数字的方法; 为了给该方法一个存储数字的位置,我们会改为传递它。
整数文字(2,3)也是不可变的,例如int var=3;
它是可变的int
变量(左边的var
有侧)。 Integer的意图是“对象作为值”(右侧)而不是“对象作为变量”(左侧)。 由于Java使用引用,因此可变性可以在引用中或在对象内容中。 对象引用( Integer r=2;
变量r
Integer r=2;
)可以是变量部分。 结果,通过变量引用提供可变性,而不是使用常量引用(常量r
)和引用对象的可变内容。 他们可以使用类名Integer
作为变量,但是对于不可变(右侧值)则需要另一个类名。 所以MutableInteger
和ImmutableInteger
都在某些点的程序中使用。 然而,人们碰巧经常使用后者。 因此,早期Java开发人员决定使用较短的名称Integer作为后者( ImmutableInteger
)。 有很多原因导致后者certificate更有用,这在本文的其他答案中有所解释。 两者都是可能的,它们都存在,只是对后者有更多的需求。