当前位置:  开发笔记 > 编程语言 > 正文

不可变类应该是最终的?

如何解决《不可变类应该是最终的?》经验,为你挑选了4个好方法。

它在本文中说:

让一个类成为最终因为它是不可变的是这样做的一个很好的理由.

我对此感到有点困惑......我理解不变性是线程安全性和简单性的POV中的好东西,但似乎这些问题与可扩展性有些正交.那么,为什么不变性成为最终上课的一个很好的理由呢?



1> Vinoth Kumar..:

"有效Java"一书中给出了对此的解释.

考虑BigDecimalBigIntegerJava中的类.

它并没有被广泛了解,一成不变的类必须是有效时,最终BigIntegerBigDecimal编写,因此他们所有的方法可能会被改写.不幸的是,在保留向后兼容性的同时,这无法得到纠正.

如果编写一个类,其安全性取决于来自不可信客户端的BigInteger或BigDecimal参数的不变性,则必须检查该参数是否为"真实"BigInteger或BigDecimal,而不是不受信任的子类的实例.如果是后者,则必须在假设它可能是可变的情况下进行防御性复制.

   public static BigInteger safeInstance(BigInteger val) {

   if (val.getClass() != BigInteger.class)

    return new BigInteger(val.toByteArray());


       return val;

   }

如果允许子类,则可能会破坏不可变对象的"纯度".



2> Garth Gilmou..:

根据Liskov替换原则,子类可以延伸但从不重新定义其父类的合同.如果基类是不可变的,那么很难找到其功能可以在不违反合同的情况下有效扩展的示例.

请注意,原则上可以扩展不可变类并更改基本字段,例如,如果基类包含对数组的引用,则不能将数组中的元素声明为final.显然,方法的语义也可以通过覆盖来改变.

我想你可以将所有字段声明为私有,并将所有方法声明为final,但那么继承的用途是什么?



3> cynicalman..:

因为如果这个类是最终的,你不能扩展它并使它变得可变.

即使您将字段设为final,这只意味着您无法重新分配引用,也不意味着您无法更改引用的对象.

我并没有在设计中看到很多用于不可变类的应该扩展的类,所以final有助于保持不变性.


作为调用者,您不知道您是使用不可变类还是其可变子类 - 除非您碰巧直接调用构造函数.这是多态性.
但是您可能希望扩展不可变类以添加其他immutbale属性.
"因为如果类是final的,你不能扩展它并使它变得可变"但是你不能扩展非最终的不可变类并使它变得可变,你只能使子类可变

4> Steve Jessop..:

我认为主要是安全性.出于同样的原因,String是final,任何与安全相关的代码都希望将其视为不可变的东西必须是最终的.

假设您有一个定义为不可变的类,请将其命名为MyUrlClass,但不要将其标记为final.

现在,有人可能会像这样编写安全管理器代码;

void checkUrl(MyUrlClass testurl) throws SecurityException {
    if (illegalDomains.contains(testurl.getDomain())) throw new SecurityException();
}

以下是他们在DoRequest(MyUrlClass url)方法中的内容:

securitymanager.checkUrl(urltoconnect);
Socket sckt = opensocket(urltoconnect);
sendrequest(sckt);
getresponse(sckt);

但他们不能这样做,因为你没有让MyUrlClass最终成功.他们不能这样做的原因是,如果他们这样做,代码可以简单地通过覆盖getDomain()在第一次调用时返回"www.google.com"来避免安全管理器限制,并且"www.evilhackers.org"第二个,并将其类的对象传递给DoRequest().

顺便说一句,如果它存在的话,我没有反对evilhackers.org的内容......

在没有安全问题的情况下,一切都是为了避免编程错误,当然由你来决定如何做到这一点.子类必须保持父母的合同,不变性只是合同的一部分.但是如果一个类的实例应该是不可变的,那么将它作为final是一种很好的方法来确保它们确实都是不可变的(即没有可变的子类实例,它们可以在父类的任何地方使用类被称为).

我不认为你引用的文章应该被视为"所有不可变类必须是最终的"的指令,特别是如果你有充分的理由设计你的不可变类继承.它所说的是保护不变性是最终的一个正当理由,其中虚构的性能问题(这是它在那时真正谈论的)是无效的.请注意,它给出了"一个不是为继承而设计的复杂类"作为同样有效的理由.可以肯定的是,在复杂类中没有考虑继承是一件可以避免的事情,就像在不可变类中没有考虑继承一样.但如果你不能解释它,你至少可以通过阻止它来表明这一事实.

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有