代码之家  ›  专栏  ›  技术社区  ›  ravinder reddy

Java中的不可变类

  •  3
  • ravinder reddy  · 技术社区  · 11 年前

    根据许多文档,我发现不可变类应该具有以下特性:

    1. 这堂课应该是最后一堂课

    2. 所有的方法都应该是最终的

    3. 所有变量都应该是最终变量

    4. 不应该有任何二传手

    但我的问题是:

    1. 如果我有一个只有最终变量的类呢?

    2. 如果我也有setter,我就不能改变Object的状态,因为我有所有的最终变量。那么这将如何影响不变性呢?

    3. 在这种情况下,继承如何更改对象状态?

    3 回复  |  直到 11 年前
        1
  •  4
  •   aioobe    11 年前

    1.如果我只与 final 变量?

    这会让你走得很远,但不会一直走下去。这些变量的类型也需要是不可变的。例如,考虑

    class MyImmutableClass {
        // final variable, referring to a mutable type
        final String[] arr = { "hello" };
    
        // ...
    }
    

    这允许某人

    myImmutableObject.arr[0] = "world";
    

    并有效地变异不可变类的对象。

    此外,建议禁止扩展类(因为没有办法强制子类是不可变的)。请参阅下面第三个问题的答案。

    1. 如果我也有setter,我就不能改变Object的状态,因为我有所有的最终变量。那么这将如何影响不变性。

    这是正确的。如果所有变量都是final,那么标准setter方法就不可能存在。

    1. 在这种情况下,继承如何改变对象状态?

    子类不能更改超级类的final字段的状态。但继承还有另一个问题。

    如果你有一个不可变的 Animal Dog ,以及 有一个 setDogsName 方法对对象进行变异,那么实际上您可能 动物 对象(类型 )事实上是可变的。

    换言之,如果一个不可变类是开放扩展的,那么不变性的大部分(全部)好处都会失去:如果您收到 动物 例如,作为方法的参数,不能假设它是不可变的。你不能安全地 动物 对象作为哈希图中的键等。


    基本上,原始语句有点多余,这就是为什么我认为它们有点混乱的原因:

    • A. 最终的 类不能扩展,因此将方法标记为 最终的
    • 如果所有变量都是final,那么说不应该有setter是多余的。

    此外,这些是 足够的 约束,但不是 必需的 例如,您可以拥有不可变的类,而不需要最终变量/最终字段类型,只要它们是私有的,从不在内部更改,也从不泄露给外部。

        2
  •  2
  •   TheLostMind    11 年前

    如果我也有setter,我不能更改Object的状态,As 我有所有的最终变量。那么这将如何影响免疫性。

    final 位于 参考 水平和 不变性 位于 例子 数量

    class someMutableClass{
    final List someList;
    }
    

    在上面的代码中。如果列表引用转义,则任何人都可以执行以下操作: someList.add(someValue)

    但他们无法做到:

    someList=someOtherList;
    

    这就是区别。

    在这种情况下,继承如何改变对象状态?

    子类可以访问父类的某些字段,然后对其进行更改。您可以使父类引用指向子类对象并修改其字段。因此,为了确保不变性,必须确保子类不会改变父类中的任何内容。所以就这样吧 最终的 .

        3
  •  2
  •   Stephen C    11 年前

    不可变类是您无法更改的类。实现不变性是消除改变对象状态的可能方法的问题。这可以通过结构和行为手段的结合来实现。


    但首先,让我们看看“应该拥有”列表:

    • “课程应该是最终的”-这可能是可取的,但可能不是严格必要的。。。或者甚至是理想的。一个实例 1. 类的实例可以是不可变的,即使某些子类的实例是可变的。这一切都取决于哪些课程 需要 这取决于上下文。

    • “所有方法都应该是最终的”——既不必要也不充分。如果类是 final 那么这是不必要的。如果该类不是 最终的 ,那么这是不够的。(您可以在子类中添加具有不同签名的方法。)

    • “所有变量都应该是最终的”-既不必要也不充分。您可以有一个不可变的类,其字段不是 最终的 ,以及一个可变类,其字段均为 最终的 .

    • “不应该有任何setter”——这取决于你所说的“setter”是什么意思,但再次强调,这既不必要(对于某些可变性模型),也不充分。


    您的问题:

    1) 如果我有一个只有最终变量的类呢?

    这不足以保证不变性。例如,如果最终变量之一是数组,则可以更改该数组的状态,从而更改整个对象的状态。这可以通过setter(或类的任何其他方法)完成,或者如果类是“泄漏抽象”,则可以通过外部代码完成。

    2) 如果我也有setter,我就不能改变Object的状态,因为我有所有的最终变量。那么这将如何影响免疫性。

    见上文。将所有字段声明为 最终的 不是不变性的保证。setter可以更改mutable的状态 组成部分 对象的。

    3) 在这种情况下,继承如何改变对象状态?

    它不能 1. 。但这不是重点。

    创建不可变类的原因 最终的 是阻止某人创建 可变子类 在课堂上。

    这有什么关系?

    好吧,假设一个方法 要求 参数是不可变的(例如为了安全)。如果您使用不可变类声明它 最终的 ,然后有人创建一个可变的子类,并传递该子类的一个实例,而不是原始的不可变类。

    这是(例如) String 类是 最终的 .


    1-我需要证明这一点。这取决于我们是否在讨论类为 A ,或关于与类型兼容的实例 A. 。我说的是前者。存在可变子类的事实确实会影响类为 A. .