请举例说明我可以看到不可变对象的优点。我在互联网上发现的信息集中在线程中。我还不知道线程。如果示例使用简单的原则
会很棒答案 0 :(得分:11)
不可变性在多线程程序中很重要,因为你知道一个线程不会破坏另一个线程中使用的值。但它在单线程程序中也很有用。
这是一个简单的例子:
Integer i=Integer.valueOf(17);
foo(i);
bar(i);
您可能想知道,传递给bar()的值是什么?
假设foo()是一个很大的复杂函数。在这个例子中,我知道一个绝对的事实,当foo完成时,我仍然等于17,因为整数是不可变的。如果不是这样,我将不得不研究foo来判断它是否会被改变。
这是一个稍微复杂的例子。假设我有一些类似于Integer的对象,但是它是可变的。我们称之为MutableInteger。然后说我写这个:
MutableInteger currentInventory=findQtyInInventory();
MutableInteger neededInventory=currentInventory; // copy current for starters
... bunch of other code ...
neededInventory.subtract(allocatedToSales);
currentInventory.add(arriving);
... bunch of more code ...
if (neededInvenory.compareTo(currentInventory)>0)
display("Shortage!");
您是否看到上述问题? neededInventory和currentInventory指向同一个对象。所有的加法和减法实际上都是在相同的值上,而不是两个不同的值,所以当我们进行测试时,它总是相等的。如果对象是可变的,上面的代码将永远不会工作。如果它们是不可变的,则add和subtracts必须返回一个结果对象而不是就地更新,这样就可以了。
多年前我使用Fortran编译器,其中整数是可变的。我们有一个接受几个参数的函数,其中一个是整数。在极少数情况下,函数更新整数。然后有一天有人写了一个对这个函数的调用,将常量“2”作为整数传递。该函数决定更新参数,从而将“常量”2改为1!程序中使用常量2的每个其他位置现在神秘地得到值1。这花了很长时间来调试。
答案 1 :(得分:3)
这不是一个可以通过示例有用地解释的概念。不可变对象的优点是你知道他们的数据不能改变,所以你不必担心。您可以自由地传递它们,而不必记住传递它们的方法是否可以以您的代码不准备处理的方式更改它们。这使得处理不可变数据变得更容易。
对于多线程,这个优势更为重要,因为基于多个线程以不应该更改的方式更改数据的错误通常是不可重现的 - 它们依赖于时序,因此有时会发生,有时不会发生,这使得它们非常重要难以分析和修复。
答案 2 :(得分:1)
当对象通常被共享时,不可变对象很有用 - 不仅仅是线程,而且在单线程程序中,对象也有很多客户端。
例如,String
可能是Java中使用最多的不可变对象。阻止该字符串的用户更改其内容是不可改变的。如果String
是可变的,则意味着每个用户都必须创建该字符串的唯一副本,以确保没有其他人正在更改它。
不可变数据也具有安全隐患。例如,与用户关联的安全令牌应该是不可变的,否则恶意程序可以轻松更改与该令牌关联的用户。
答案 3 :(得分:1)
正如您所知,这是多线程的一个很好的模式。
这也意味着更好的封装。您可以传递这些对象并共享它们,您永远不必担心有人会更改对象的状态。
Java核心库中有一些很好的例子。数字子类是一个,但我认为最好的例子是String
。你传递它们,连接,得到子串等,永远不需要考虑其他地方。如果它像C / C ++ char[]
一样可变,你总是需要牢记这一点。
出于同样的原因,它还会导致更具可读性和可维护性的代码。无需关心对象的其他用户。
这两个原因导致我们进入另一个称为 Value Object 的重要模式。简而言之,当您关心某个特定值(日期,数字,字符串,间隔,金钱或某些稍微复杂的对象,如果您需要)时,它是有意义的,但是值本身没有标识,即无论上下文如何,它都具有完全相同的含义。
答案 4 :(得分:1)
当Java按值返回时(即从方法返回对象引用),如果我返回一个如下所示的字符串:
private String myString = "foo";
public String getString() {
return this.myString;
}
并且String类不是不可变的,那么getString()
的调用者可以修改myString
,这可能不是所需的行为;系统的其他部分可能不希望或期望myString
更改。因此调用者只能更改myString
指向的对象,而不是myString
本身。
答案 5 :(得分:1)
这是一种同义反复,但不可变对象的主要优点是它们无法改变。当对象可以改变时,你必须考虑它们可能发生的事情。你必须考虑如何,何时以及为什么要改变它们。您必须考虑应用程序中的其他代码可能访问同一对象的内容,以及在您不知情的情况下可能会更改的内容。不可变对象有效地减少了您必须在系统中进行操作的“移动部件”的数量(和粒度),并使您的生活更轻松。
答案 6 :(得分:0)
这里的主要思想是通过使用不可变对象使您的类线程安全。我认为article对此很好。
希望这有帮助!
答案 7 :(得分:0)
一个很好的例子是String
类:
可以找到here
的不可变对象原因的一个很好的总结