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的行为不正确。