【发布时间】:2010-05-17 22:43:29
【问题描述】:
您经常读到不可变对象要求最终字段在 Java 中是不可变的。事实是这样吗,还是仅仅没有公共可变性而不实际改变状态就足够了?
例如,如果您有一个由构建器模式构建的不可变对象,您可以通过让构建器在构建时分配各个字段来做到这一点,或者让构建器自己保存字段并最终通过传递返回不可变对象其(私有)构造函数的值。
拥有 final 字段具有防止实现错误的明显优势(例如允许代码保留对构建器的引用并多次“构建”对象,同时实际上改变现有对象),但让构建器存储其构建时对象内部的数据似乎是 DRYer。
所以问题是:假设 Builder 不会及早泄漏 Object 并且一旦构建就停止修改对象(例如通过将其对对象的引用设置为 null)实际上是否有任何收获(例如提高线程安全性)如果将对象的字段设为最终字段,则对象的“不变性”?
【问题讨论】:
-
如果我没记错的话,final 还可以帮助防止流氓程序员使用反射访问类的字段并修改其内容的“反射攻击”。有一个著名的例子完全颠倒了 String 类,并表明在很多情况下 String 实际上可以被修改(如果不是由于非最终性,而是由于事实上,一旦底层 char[] 被访问,如果“游戏结束”,因为你不能强制数组内容的不变性......但这不是我的意思:我的意思是反射可以帮助做讨厌的东西)。
-
@user,面对这样的反思,你无法建立不变性。然而,安全管理器的目的是让运行这样的第三方代码变得可行。
-
等等...如果我有一个具有唯一 final int 的 final 类,您可以使用反射来修改它吗?我的观点正是没有使用final你不能防止反射攻击(除非你有一个Security Manager,但它几乎从来不是案例,这就是为什么我写了“在很多情况下都可以修改”...)。但是,我不确定您是否可以使用反射来修改 final int ...你昨天的问题顺便说一句:)
-
@user988052,抱歉直到现在才看到您的评论。您可能无法设置原语(与将其编译为常量有关),但您可以更改对象引用 - 如果它不是静态的,则在 1.5 和 1.6 中。见javaspecialists.eu/archive/Issue096.html。
标签: java immutability