我知道整数在Java中是不可变的。但为什么这样设计呢?
在提出这个问题之前,我先回答了其他问题:
i++ still working for immutable Integer in Java?
Why are Java wrapper classes immutable?
但我无法找到强制整数为永久不变的用例。 是否存在类似String的技术原因?
我知道像AtomicInteger
这样的包装器是可变的。
更新:
从对话中,没有普遍的理由可以强制整数是不可变的。然而,通过做不变量,它提供了答案中提到的一些奖励。
例如来自Andrey
的引用缓存的可能性。
其他人正在减少全球状态
更容易多线程
答案 0 :(得分:19)
您找不到java.lang
包装器必须不可变的强制性原因。仅仅因为这是一个设计决策。他们本来可以做出决定。语言设计者必须在 mutable 和 immutable 之间进行选择。他们选择了 immutable 。就是这样。
虽然有一些引人注目的(IMO)理由让它们不可变:
与String
一致。您为String
不可变提供的相同推理也适用于Integer
等(例如,考虑属性映射中的端口号)。 这通常适用于任何可变类型。
不可变的类型排除了过多的难以发现的错误,可以通过修改通过 getter 获得的值来非自愿地更改对象成员值。 当类型不可变 时,它可以节省大量的防御性复制。最臭名昭着的例子是java.util.Date
,这通常很难使用,因为它是可变的(除了API问题)。
同样不可变类型允许使用共享实例,例如Integer
适用于常用值(请参阅Integer.valueOf(int)
)。
答案 1 :(得分:4)
值1
的标识是否会发生变化?可以成为2
吗?不。这就是Integer
和其他数字类型不可变的原因。他们的意图是塑造这种身份。
答案 2 :(得分:0)
为了使对象引用封装一个受持有它的东西控制的值,必须应用以下三个条件之一:
对象的类必须是不可变的。
引用必须标识一个永远不会暴露于任何可能使其变异的实例。
绝不能与任何不受其持有人控制的对象共享引用,无论这种对象是否会发生变异。
保存类型Integer
的引用的代码通常是为了封装整数值。使Integer
不可变使得类可以自由地共享用于封装值的引用。虽然有时MutableInteger
类本身有用[这样的事情可能比单个元素int[]
更清晰一些,并且效率高于AtomicInteger
],但是#39; t将MutableInteger
类传递给方法,作为传递数字的方法;为了给该方法一个存储数字的地方,我们会传递它。
答案 3 :(得分:0)
整数文字(2,3)也是不可变的,例如int var=3;
这是int
变量(左边的var
有侧面)是可变的。 Integer的意图是“作为价值的对象”(右侧)而不是“作为变量的对象”(左侧)。由于Java使用引用,因此可变性可以在引用中或在对象内容中。对象引用(r
中的变量Integer r=2;
)可以是变量部分。结果,通过变量引用提供可变性,而不是使用常量引用(常量r
)和引用对象的可变内容。他们可以使用类名Integer
作为变量,但是对于不可变(右侧值),则需要另一个类名。因此MutableInteger
和ImmutableInteger
在某些方面都用于程序中。然而,人们碰巧经常使用后者。因此,早期Java开发人员决定使用较短的名称Integer作为后者(ImmutableInteger
)。有很多原因导致后者变得更有用,这在本文的其他答案中有所解释。两者都是可能的,它们都存在,只是对后者有更多的需求。
答案 4 :(得分:0)
我认为不变性是一种与垃圾收集机制相关的设计选择。至少,不变性有助于垃圾收集更有效地工作,因为消除了需要采取的几种开销机制来保证对象的完整性。
早期的编程语言是在硬件约束的限制非常明显的时代发明的(例如 RAM 和处理器速度以及没有运行时/裸机方法)。在这样的环境中,您需要非常小心地进行对象实例化,并且一旦实例化,您应该更新它而不是丢弃新值。在这方面,JAVA 是推广具有运行时和垃圾收集的新方法的先驱之一 - 这与不变性齐头并进。
请注意,最近使用 Python 等字节码的解释器(而不是 Perl)也使用整数和简单类型的不变性。
<块引用>程序员通常不愿意使用不可变对象,因为他们担心创建新对象而不是更新对象的成本。对象创建的影响通常被高估,并且可以被与不可变对象相关的一些效率所抵消。其中包括因垃圾收集而减少的开销,以及消除保护可变对象免遭损坏所需的代码。