java:示例中不可变对象的优点

|                                                                                                                       
已邀请:

bab

不变性在多线程程序中很重要,因为这样您就知道一个线程不会破坏另一个线程中使用的值。但它在单线程程序中也很有用。 这是一个简单的示例:
Integer i=Integer.valueOf(17);
foo(i);
bar(i);
您可能想知道,什么值传递给bar()? 假设foo()是一个大型复杂函数。在此示例中,我绝对知道foo完成时,我仍然等于17,因为Integer是不可变的。如果不是真的,我将必须研究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指向同一对象。所有的加法和减法实际上都作用于相同的值,而不是两个不同的值,因此,当我们进行测试时,它将始终相等。如果对象是可变的,则上面的代码将永远无法工作。如果它们是不可变的,则加法和减法将必须返回结果对象,而不是就地更新,这将起作用。 多年前,我使用了Fortran编译器,其中整数是可变的。我们有一个接受几个参数的函数,其中一个是整数。在极少数情况下,函数会更新整数。然后有一天,有人对此函数进行了调用,将常量“ 2”作为整数传递。该函数决定更新参数,从而将“常量” 2更改为1!程序中使用常数2的每个其他位置现在都神秘地取值为1。这花费了很长时间进行调试。     
这不是一个可以通过示例进行有用解释的概念。不变对象的优点是您知道它们的数据无法更改,因此您不必为此担心。您可以自由地传递它们,而不必记住传递给它们的方法是否可能以您的代码不准备处理的方式更改它们。这使得处理不可变数据变得更加容易。 对于多线程而言,这一优势更为重要,因为基于多线程以不应该更改的方式更改数据的错误通常是不可重现的-它们依赖于时序,因此有时会发生,有时甚至不会,这使得它们非常难以分析和修复。     
当Java按值返回时(即对象引用是从方法返回的),例如,如果我返回一个String像这样:
private String myString = \"foo\";

public String getString() {
    return this.myString;
}
并且String类不是不可变的,则
getString()
的调用者可以修改
myString
,这可能不是所需的行为;系统的其他部分可能不希望或期望ѭ4更改。因此,调用者只能更改
myString
指向的对象,而不能更改
myString
本身。     
这是重言式的,但是不可变对象的主要优点是它们不能更改。当对象可以更改时,您必须考虑它们可能会发生什么。您必须考虑如何,何时以及为何要更改它们。您必须考虑应用程序中还有哪些其他代码可以访问同一对象,以及在不知情的情况下可能会更改什么。不可变的对象有效地减少了您必须在系统中使用的“活动部件”的数量(和粒度),并使您的生活更轻松。     
如您所知,这是多线程的绝佳模式。 这也意味着更好的封装。您可以传递这些对象并共享它们,而您永远不必担心有人会更改您对象的状态。 Java核心库中有一些很棒的例子。数字子类是一个,但我认为最好的例子是
String
。您可以将它们传递,连接,获取子字符串等,而无需考虑其他地方。如果它像C / C ++
char[]
一样易变,则始终需要牢记这一点。 出于相同的原因,它还导致了更具可读性和可维护性的代码。无需关心对象的其他用户。 这两个原因导致我们进入另一个重要的模式,称为值对象。简而言之,当您关心某个特定值(日期,数字,字符串,间隔,金钱或一些稍微复杂的对象(如果需要))时,这很有意义,但是值本身没有身份,即它具有无论上下文如何,其含义完全相同。     
当对象通常被共享时,不可变对象非常有用-不仅与线程共享,而且在单线程程序中,对象也具有许多客户端。 例如,
String
可能是Java中使用最多的不可变对象。阻止该字符串的用户更改其内容是不变的。如果“ 8”是可变的,则意味着每个用户都必须创建该字符串的唯一副本,以确保没有其他人对其进行更改。 不变的数据也具有安全隐患。例如,与用户关联的安全令牌应该是不可变的,否则流氓程序可能会轻易更改与该令牌关联的用户。     
这里的主要思想是通过使用不可变对象使您的类线程安全。我认为这篇文章对此很不错。 希望这可以帮助!     
String
类就是一个很好的例子: 关于不可变对象的原因的很好总结可以在这里找到     

要回复问题请先登录注册