Java final修饰符
我被告知,我误解了final
影响。 final
关键字有什么作用?
这里是我所想,我知道的简短概述:
Java final修饰符(又名聚合关系)
原始variables :只能设置一次。 (内存和性能增益)
对象variables :可能被修改,最终适用于对象引用。
字段 :只能设置一次。
方法 :不能被覆盖,隐藏。
类 :不能扩展。
垃圾收集 :将强制Java代垃圾收集标记扫一扫。
可以和不可以的
- 可以使克隆失败(这是好的和坏的)
- 可以使不可变的原语又称为const
- 可以使空白不变 – 初始化创buildaka只读
- 可以使对象浅不可变
- 可以使范围/可见性不可变
- 可以使方法调用开销更小(因为它不需要虚表)
- 可以使方法论点作为最终(即使你不是)
- 可以使对象线程安全(如果对象被定义为最终的,它不会使方法参数最终)
- 可以做模拟testing(不是你可以做任何事情 – 你可以说错误是有意的)
- 不能交朋友(可以和其他朋友一起rest,不可改变)
- 不能做可变以后更改为不可变(但可以像修复工厂模式)
- 不能使数组元素永远不可变,即不可变的
- 无法创build对象的新实例(这是好的和坏的)
- 无法使序列化工作
没有final
,但有包装+私人和枚举。
依次回答你的每一点:
原始variables:只能设置一次。 (内存和性能增益)
是的,但没有记忆收益,没有性能增益。 (你所期望的性能增益来自于只设置一次…而不是从final
。)
对象variables:可能被修改,最终适用于对象引用。
是。 (但是,这种描述忽略了这一点,即与Java语言其余部分处理对象/引用对偶的方式完全一致,例如,当对象作为parameter passing并作为结果返回时)。
字段:只能设置一次。
真正的答案是:与variables相同。
方法:不能被覆盖,隐藏。
是。 但是还要注意,这里发生的事情是final
关键字被用在不同的语法上下文中,意味着与字段/variables的final
不同。
类:不能扩展。
是。 但是还要看上面的注释。
垃圾收集:将强制Java代垃圾收集标记扫一扫。
这是无稽之谈。 final
关键字与垃圾回收没有任何关系。 你可能会混淆final
…他们是无关的。
但即使是终结者,也不会强加额外的扫荡。 发生什么事是一个需要完成的对象被设置在一边,直到主GC完成。 GC然后在对象上运行finalize方法并设置其标志…并继续。 下一次GC运行时,该对象被视为普通对象:
- 如果可以访问,则会被标记并复制
- 如果不可达,则不标记。
(您的表征 – “Java世代垃圾收集标记扫描”是乱码垃圾收集器可以是“标记扫描”或“代”(“复制”的子类),它不能同时存在。在紧急情况下,也就是在空间不足时,或者一个低度停顿的收集者不能跟上的时候,才会回到标记清除状态。
可以使克隆失败(这是好的和坏的)
我不这么认为。
可以使不可变的原语又称为const
是。
可以使空白不变 – 初始化创buildaka只读
是的,虽然我从来没有听说过使用过“空白不变的”这个词。
可以使对象浅不可变
对象可变性是关于可观察状态是否可能改变。 因此,声明属性final
可能会或可能不会使对象的行为不可变。 除了“浅不可变”这个概念还没有很好的定义,不仅仅是因为如果没有深入的类语义知识,“浅”的概念就不能被映射。
(显而易见,variables/字段的可变性是JLS环境中一个明确定义的概念,它只是从JLS的angular度来看未定义的对象的可变性概念。)
可以使范围/可见性不可变
术语错误。 可变性是关于对象状态的。 可见性和范围不是。
可以使方法调用开销更小(因为它不需要虚表)
在实践中,这是无关紧要的。 一个现代的JIT编译器也为非final方法做了这种优化,如果它们没有被应用程序实际使用的任何类覆盖的话。 (聪明的东西发生…)
可以使方法论点作为最终(即使你不是)
咦? 我无法parsing这句话。
可以使对象线程安全
在某些情况下是的。
(如果对象被定义为final,则不会使方法参数最终)
是的,如果你的意思是class级是最终的。 对象不是最终的。
可以做模拟testing(不是你可以做任何事情 – 你可以说错误是有意的)
不parsing。
不能交朋友(可以和其他朋友一起rest,不可改变)
Java没有“朋友”。
不能做可变以后更改为不可变(但可以像修复工厂模式)
是的,第一, final
字段不能从可变的切换到不可变的。
目前还不清楚第二部分的含义。 确实,您可以使用工厂(或生成器)模式来构build不可变对象。 但是,如果您在对象字段中使用final
,那么对象将不可变。
或者,您可以实现使用非final字段来表示不可变状态的不可变对象,并且您可以deviseAPI,以便您可以“翻转开关”以使先前可变对象从现在开始不可变。 但是如果你采取这种方法,你需要更加小心的同步…如果你的对象需要线程安全。
不能使数组元素永远不可变,即不可变的
是的,但是你的术语被打破了; 请参阅上面有关“浅层可变性”的评论。
无法创build对象的新实例(这是好的和坏的)
不,没有什么能阻止你用final字段或最终类或最终方法创build对象的新实例。
无法使序列化工作
没有序列化的作品。 (当然,使用自定义readObject
方法对final
字段进行反序列化存在问题,尽pipe您可以使用reflection黑客来解决它们。)
没有最后的select,
正确。
但有包装+私人
是的,模(严格来说)非最终字段的非同步getter可能是非线程安全的… 即使它在对象构造期间被初始化,然后永远不会改变 !
和枚举。
解决一个不同的问题。 enums
可以是可变的。
最终关键字通常用于保存不变性。 对类或方法使用final是为了防止方法之间的联系中断。 例如,假设类X的某些方法的实现假设方法M将以某种方式performance。 将X或M声明为final将防止派生类重新定义M,从而导致X的行为不正确。