Java中的不变性

时间:2013-11-21 22:07:56

标签: java immutability

我正在尝试将事物放在“immutability”的定义中。

Item(3)here说,作为创建不可变对象的规则之一,

  

不允许子类重写方法。最简单的方法   是将该类声明为final。 ...

重写的方法在子类的实例上运行。 而且,据我所知,一个不可变类是其中一个对象在实例化后被“雕刻”在内存中 - 没有任何成员因此无法更改对象。

将这些放在一起 - “immutable”的定义是否适用于类和对象?通过最终确定方法,我阻止其方法在扩展类时被覆盖。我没有看到如何最终确定不可变类的方法进一步增加使其对象不可变。

7 个答案:

答案 0 :(得分:7)

如果您将类记录为不可变类,则此类的用户可以安全地假设此类的任何实例都是不可变的。

问题在于,如果允许对类进行子类化,则不禁止子类添加可变状态和方法,甚至不要覆盖方法并使它们改变这种新状态。因此,该类用户的假设崩溃了。让课程最终成为不可能的事。

答案 1 :(得分:1)

final关键字的设备存在很大差异。

...电器

  • ... 禁止进行子类化(因此,方法覆盖也是如此)
  • ...到方法禁止方法覆盖
  • ...到实例变量确保这些字段的不变性,因此也适用于整个对象,如果为所有字段指定的话,因为最终变量只能写入一次,构造

文档:

答案 2 :(得分:1)

  

我不知道如何最终确定不可变类的方法,以进一步增加使其对象不可变。

如果某个类为final,则其方法final是多余的;因为没有任何东西可以从类派生,所以没有任何东西可以覆盖方法,无论它们是否被声明final。如果您定义的类是不可变的,如果它是final,则不能有任何不可变的子类(因为根本不存在任何子类)。

答案 3 :(得分:1)

我想如果一个类的对象是不可变的,那么你可以说这个类也是不可变的。 String个对象是不可变的,所以你可以说String类是不可变的。

当你创建方法final时,你会阻止一些未知的子类执行以下操作:

@Override
public void yourMethod() {
    doSomeMutableThing();
}

它阻止子类使用继承和多态来改变(更改)类中的数据。它还可以防止子类引入自己的某些状态,这可能是可变的。

不可变性不是你可以宣布的;您必须使用Java语言内置的几种技术来强制执行它。制作方法final就是其中之一。

答案 4 :(得分:1)

  

“immutable”的定义是否适用于类以及   对象

看到class是一个对象的蓝图,是吗?

这里要做的更重要的区别是 - 在任何地方添加final都不会使你的类/对象不可变。一点都不。

考虑一下:

final class Foobar {
  /*
   * in this context, final just means you can't rebind the variable.
   * it doesn't make the list immutable.
   */
  final List<String> notReallyImmutableList; 
  Foobar() {
    notReallyImmutableList = new ArrayList<String>();
  }

  final void addToList(String string) {
    notReallyImmutableList.add(string);  // totally legit if you have an instance of Foobar
  }
}

答案 5 :(得分:1)

不可变意味着对象不能改变。因此Java中的标准String对象是不可变的 - 您可以传递它,您可以根据需要保存尽可能多的引用但不能修改它。如果你想修改一个字符串,你可以使用StringBuilder(或StringBuffer)来附加或修改它。

但String是一个内部系统提供的类,因此它的不变性可以从表面上看。如果您希望创建一个不可变类,那么您只能通过提供保证不修改其内部状态的方法来实现。由于类通常是可覆盖的,因此可以想象一段代码可能只是为了修改内部状态而对类进行子类化。

因此:

  1. 将所有字段设为内部隐私。它们也应该被标记为final,因为它们只能从构造函数中设置。
  2. 不要返回任何本身就是对象的字段,除非它们也是不可变的。
  3. 标记对象最终和所有方法最终
  4. 不提供任何可以修改内部状态的方法
  5. 吐出新对象的clone(),add(),subtract(),split(),diff(),combine()等操作不应该引用现有对象或其字段以保证安全。使用深层副本以确保它们是线程安全的。
  6. 如果您的对象返回其他对象的集合,则使用Collections.unmodifiableList(),unmodifiableMap()等方法来阻止人们滥用这些集合。
  7. 同样,如果对象或任何字段实现了为读/写操作设计的接口,则在执行任何写操作时抛出异常。
  8. 不可变性对于对象来说是一个很好的质量(特别是那些所有权可能是一个问题,或者是并发性的),但缺点是你可能会构造很多一次性对象,因此它们可能效率低下。所以这是一个权衡,它取决于你需要的对象是否值得。

答案 6 :(得分:0)

对象定义行为和状态。不变性是指一旦创建的对象不会改变其内部状态。

这使得更容易使用线程,除了其他优点之外,这里是一个来自不可变列表的番石榴的例子。 我发布新链接后无法发布链接... http://google-collections.googlecode .com /svn/trunk/javadoc/com/google/common/collect/ImmutableList.html

所以要回答你的问题,最终确定方法会限制继承,但不会限制不变性。