Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 可变类作为不可变类的子类_Java_Oop_Inheritance_Immutability_Mutable - Fatal编程技术网

Java 可变类作为不可变类的子类

Java 可变类作为不可变类的子类,java,oop,inheritance,immutability,mutable,Java,Oop,Inheritance,Immutability,Mutable,我希望有如下不可变的Java对象(高度简化): 在某些情况下,对象不仅应该是可读的,而且应该是可变的,因此我可以通过继承添加可变性: public class Mutable extends Immutable { public Mutable(String name) { super(name); } public void setName(String name) { super.name = name; } } 虽然这

我希望有如下不可变的Java对象(高度简化):

在某些情况下,对象不仅应该是可读的,而且应该是可变的,因此我可以通过继承添加可变性:

public class Mutable extends Immutable {

    public Mutable(String name) {
        super(name);
    }

    public void setName(String name) {
        super.name = name;
    }

}
虽然这在技术上很好,但我想知道它是否符合OOP和继承,即可变的类型也是不可变的。我希望避免像Java collections API那样,为不可变对象抛出
UnsupportedOperationException
,从而导致OOP犯罪


你觉得怎么样?还有其他想法吗?

不可变的类应该是
final
,以避免可变的子类型

允许一个不可变类的子类型打破不可变契约,使得让该类在一开始是不可变的变得毫无意义。从Java允许您这样做的意义上讲,这可能是合法的(语言中不强制执行不可变性),但这样的类并不是真正不可变的,只要它可以被子类化

这就是为什么字符串是最终的。

避免调用父类“不可变”,因为它在子类中成为谎言-如果您确实想使类不可变,那么它也应该是最终的,以便准确地防止此问题

Joda Time使用“ReadableXXX”来表示“这个类只提供读访问;其他子类可能是可变的”。我不确定我是否喜欢这个主意,但我不能说我已经看到了很多选择


基本上,问题在于表达一个否定的-
不可变的
描述了你不能做的事情(对它进行变异)以及不能在子类中合理地强制执行的事情。(即使
Immutable
中的字段是final,它也不会阻止子类拥有自己的可变字段。)

我发现您的代码相当奇怪

为了实现这种不可变的行为,我宁愿依赖于
不可变的
接口,只提供getter方法,而对象包含这两种方法。这样,依赖于不可变对象的操作将调用接口,而其他操作将调用对象


而且,如果您真的不希望将不可变对象强制转换为可变对象,那么您可以使用代理和所有企业工具(方面,等等)。但是通常,依赖其他开发人员的善意是让他们为自己的错误负责的一种很好的方式(比如在可变中铸造不变)。

您的子类很糟糕,因为它违反了规则。不要这样做。

我建议您应该有一个可继承的基本“ReadableFoo”类、一个派生的密封ImmutableFoo类和其他派生的MutableFoo类。不关心Foo是否可变的代码可以接受ReadableFoo。想要一个保证不会更改的Foo的代码可以接受一个不可变的Foo。需要更改Foo的代码可以接受MutableFoo


注意,ImmutableFoo和MutableFoo的构造函数通常都应该接受ReadableFoo。这样,任何一个FO都将被转换成一个可变的或不可变的版本。

这正是目标C所做的:<代码> nSutuable Stords<代码>继承自<代码> NScord,<代码> NSMutableArray < /代码>继承自<代码> NSArray < /C> >等。你怎么能在这里完成基类决赛?问题是没有一个编译器能够表达模型中可能出现的所有矛盾。因此,我们应该期望编译器会为我们检查一切。代理可以被起诉使对象成为只读的,但它们不会使对象不可变。使一个可能可变的对象不可变的唯一方法是分离它的每个可能可变的部分,在这种情况下,该对象不再是一个代理。不,它不是。
Immutable
的实例可以被
Mutable
的实例替换,而不改变代码的行为。我不明白为什么这个错误的答案仍然存在,没有任何编辑。需要Immutable对象的代码需要更新以制作防御副本。否则,在某些情况下可能会发生坏事。也许从技术上讲这不是LSP,答案是正确的。在wikipedia页面上,“根据Meyer和America的定义,可变点是不可变点的行为亚型,而LSP禁止这样做。”请参阅以下内容以获得更好的解释:
public class Mutable extends Immutable {

    public Mutable(String name) {
        super(name);
    }

    public void setName(String name) {
        super.name = name;
    }

}