2 回答
TA贡献2012条经验 获得超12个赞
依次回答您的每个观点:
原始变量:只能设置一次。(内存和性能提升)
是的,但是没有增加内存,也没有提高性能。(您假定的性能提升仅来自设置一次,而不是来自final。)
对象变量:可以修改,最终适用于对象引用。
是。(但是,此描述忽略了一点,即它与其余Java语言处理对象/引用对偶性的方式完全一致。例如,当对象作为参数传递并作为结果返回时。)
字段:只能设置一次。
真正的答案是:与变量相同。
方法:不能被覆盖,隐藏。
是。但也请注意,这里发生的是该final关键字在不同的语法上下文中使用,表示与final字段/变量不同的含义。
类:无法扩展。
是。但也请参阅上面的注释。
垃圾收集:将强制Java代垃圾收集标记扫描进行两次扫描。
这是无稽之谈。该final关键字没有关联任何垃圾收集。您可能final对最终化感到困惑……它们是无关的。
但是,即使终结器也不会强制进行额外的扫描。发生的情况是,需要终结的对象放在一侧,直到主GC完成。然后,GC在对象上运行finalize方法并设置其标志...并继续。下次GC运行时,该对象将被视为普通对象:
如果可以到达,则将其标记并复制
如果无法访问,则不会被标记。
(您的特征-“ Java世代垃圾收集标记扫描”是乱码。垃圾收集器可以是“ mark-sweep”或“ generational”(“ copying”的子类)。不能同时使用。Java通常使用世代收集,并且仅在紧急情况下才退回标记扫描;即,当空间用尽或低暂停收集器无法跟上时。)
会使克隆失败(这既好又坏)
我不这么认为。
可以使不可变的原语又称为const
是。
可以使空白不可变-在创建时初始化为aka只读
是的,虽然我以前从未听说过“空白不变”这一术语。
可以使对象浅成不变
对象可变性是关于可观察状态是否可能改变。这样,声明属性final可能会使对象表现为不可变。除了“浅层不可变”的概念没有得到很好的定义,这尤其是因为没有对类语义的深入了解就无法映射“浅层”的概念。
(很明显,在JLS的上下文中,变量/字段的可变性是一个定义明确的概念。只是从JLS的角度来看,未定义对象的可变性的概念。)
可以使范围/可见性不变
术语错误。可变性与对象状态有关。可见性和范围都没有。
可以使方法调用的开销较小(因为它不需要虚拟表)
实际上,这是无关紧要的。如果未由应用程序实际使用的任何类覆盖非最终方法,那么现代JIT编译器也会对非最终方法进行此优化。(聪明的事情发生了……)
可以将方法参数用作最终参数(即使您不是)
??我无法解析这句话。
可以使对象成为线程安全的
在某些情况下可以。
(如果将对象定义为final,则不会使方法参数成为final)
是的,如果您的意思是课程是最后的。对象不是最终的。
可以进行模拟测试(不是您可以做任何事-您可以说是故意的错误)
不解析。
不能交朋友(与其他朋友可变而不能休息)
Java没有“朋友”。
以后不能使可变成为不变的(但可以使用工厂模式,如修复)
是的,第一个final字段不能从可变更改为不可变。
目前尚不清楚第二部分是什么意思。确实可以使用工厂(或构建器)模式构造不可变对象。但是,如果您final在任何时候都使用对象字段,则该对象将是可变的。
或者,您可以实现使用非最终字段表示不可变状态的不可变对象,并且可以设计API,以便您可以“翻转开关”以使从现在开始可变为先前可变的对象。但是,如果采用这种方法,则在同步时需要更加小心……如果您的对象需要是线程安全的。
不能使数组元素不可变又称为深度不可变
是的,但是您的术语不正确;请参阅上面有关“浅可变性”的评论。
无法创建对象的新实例(这既好又坏)
不会。没有什么可以阻止您使用final字段,final类或final方法来创建对象的新实例。
无法使序列化工作
否。序列化有效。(当然,final使用自定义readObject方法对字段进行反序列化会带来问题……尽管您可以使用反射技巧来解决这些问题。)
除了final,别无选择,
正确。
但是有包装+私人
是的,对非最终字段进行非同步的getter模(严格地说)可能是非线程安全的... 即使在对象构造期间对其进行了初始化,然后再也从未更改!
和枚举。
解决了另一个问题。并且enums可以是可变的。
TA贡献1817条经验 获得超14个赞
Final关键字通常用于保留不变性。将final用于类或方法是为了防止方法之间的链接断开。例如,假设类X的某些方法的实现假设方法M将以某种方式运行。将X或M声明为final将防止派生类以导致X行为不正确的方式重新定义M。
添加回答
举报