Java关键字之final

简介: Java final 关键字

1 前言

final 的意思是不变的,一般来说可以用于以下三种场景:

  1. 被 final 修饰的类,表明该类是无法继承的;
  2. 被 final 修饰的方法,表明该方法是无法覆写的;
  3. 被 final 修饰的变量,说明该变量在声明的时候,就必须初始化完成,而且以后也不能修改其内存地址。

注意:对于 List、Map 这些集合类来说,被 final 修饰后,是可以修改其内部值的,但却无法修改其初始化时的内存地址。

2 修饰的对象

final 可以用来修饰变量、字段、方法和类。

2.1 变量

可以将变量声明为 final 。final 变量的值一旦分配了就无法再修改了。在一次赋值之前,final 变量必须是明确未赋值的,否则会产生编译错误。如果 final 变量包含对对象的引用,则对象的状态可能会通过对对象的操作进行更改,但变量将始终引用相同的对象。这同样适用于数组,因为数组也是对象;如果一个 final 变量持有一个数组的对象,则可以通过对数组的操作修改数组中的元素,但是该变量始终会引用相同的数组。

注意,如果 final 用于局部变量,那么它可以不用初始化,而如果用于类中的某个字段,那么它必须进行初始化,否则会产生编译错误。

空 final 是指其声明缺少初始化器的 final 变量。

常数变量是一个用常量表达式初始化的基本类型或String类型的 final 变量。 变量是否为常数变量与类的初始化,二进制兼容性和明确赋值有关。

有三种变量会被隐式声明为 final :接口中的字段,try-with-resources 语句中的局部变量以及multi-catch子句中的异常参数。 一个单一的 catch 子句中的 exception 参数永远不会隐式声明为 final ,但是它可以被认为效果等同于 final 。

某些未被声明为 final 变量实际上可以认为效果等同于 final 变量:

  • 声明带有初始化器且满足下列所有条件的局部变量:
  • 永远不会作为赋值操作符的左操作数出现
  • 永远不会作为前缀或后缀递增或递减操作符的操作数出现
  • 声明缺少初始化器且满足下列所有条件的局部变量:
  • 无论何时它作为赋值操作符的左操作数出现,都是明确未赋过值的,并且在本次赋值操作前未被明确赋值。即它是明确未赋过值的,并且在本次赋值操作的右操作数之后未被明确赋值
  • 永远不会作为前缀或后缀递增或递减操作符的操作数出现
  • 方法、构造器、lambda 和异常参数在明确其是否可以认定为等同于 final 时可以被认为是声明带有初始化器的局部变量

如果变量在效果上等同于 final ,那么对其声明添加 final 修饰符并不会引入任何编译错误。相反地,在合法程序中被声明为 final 的局部变量和参数,如果将它们的 final 修饰符移除,那么它们在效果上会等同于 final 。

2.2 类

类可以被声明为 final ,如果一个 final 类的名字出现在另一个类声明的 extends 子句中,会产生编译错误,这意味着 final 类不能有任何子类。

如果一个类同时被声明为 final 和 abstract ,也会产生编译错误,因为这样的类是永远无法实现的。

因为一个 final 类不能有任何子类,所以 final 类的方法永远都不会被覆写。

如果将一个没有被声明的 final 类声明为 final ,那么当这个类的已有子类的二进制文件被加载时,就会抛出一个 VerifyError ,因为 final 类不能有任何子类。因此不推荐在广泛分布的类中进行这种变更。

反之,将一个声明为 final 的类不再声明为 final ,不会破坏与已有二进制文件的兼容性。

2.3 方法

方法可以被声明为 final 以阻止子类覆写或者隐藏它。

如果试图覆写或者隐藏 final 方法,会产生编译错误。

private 方法和所有在 final 类中声明的方法表现就如 final方法一样,因为它们是不可能被覆写的。

在运行时,机器码生成器或优化器可以“内联” final 方法的方法体,将方法的调用替换为其方法体中的代码。内联处理必须保留方法调用的语义。特别是,如果实例方法调用的目标为null,那么即使该方法是内联的,也必须抛出空指针异常。一个Java编译器必须确保异常在正确的位置上被抛出,这样在方法调用之前,传递给方法的实际参数将被按正确的顺序计算过。

2.4 字段

字段可以被声明为 final 。类和实例变量(static 和 非 static 字段)都可以被声明为 final。

空 final 类变量必须在声明它的类的静态初始化器中赋过值,否则会产生编译错误。

空 final 实例变量必须在声明它的类的每一个构造器的末尾赋过值,否则会产生编译错误。

参考资料

目录
相关文章
|
1月前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
28 3
|
29天前
|
存储 安全 Java
了解final关键字在Java并发编程领域的作用吗?
在Java并发编程中,`final`关键字不仅用于修饰变量、方法和类,还在多线程环境中确保对象状态的可见性和不变性。本文深入探讨了`final`关键字的作用,特别是其在final域重排序规则中的应用,以及如何防止对象的“部分创建”问题,确保线程安全。通过具体示例,文章详细解析了final域的写入和读取操作的重排序规则,以及这些规则在不同处理器上的实现差异。
了解final关键字在Java并发编程领域的作用吗?
|
1月前
|
Java 编译器
在Java中,关于final、static关键字与方法的重写和继承【易错点】
在Java中,关于final、static关键字与方法的重写和继承【易错点】
21 5
|
1月前
|
缓存 安全 Java
Java中 final、finally、finalize 有什么区别?
本文详细阐述了Java中`final`、`finally`和`finalize`的区别:`final`用于修饰类、方法和变量以表示不可变性;`finally`是用于确保在`try-catch`结构中无论是否发生异常都能执行的代码块;而`finalize`是`Object`类的方法,用于在对象被垃圾回收前执行清理工作,但在JDK 9中已被标记为弃用。
30 0
Java中 final、finally、finalize 有什么区别?
|
1月前
|
Java
Java关键字 —— static 与 final 详细解释!一看就懂 有代码实例运行!
这篇文章详细解释了Java中static和final关键字的用法,包括它们修饰类、方法、变量和代码块时的行为,并通过代码示例展示了它们的具体应用。
178 0
Java关键字 —— static 与 final 详细解释!一看就懂 有代码实例运行!
|
1月前
|
存储 安全 Java
了解final关键字在Java并发编程领域的作用吗?
了解final关键字在Java并发编程领域的作用吗?
|
1月前
|
Java 程序员 编译器
【Java】继承、super、final、子类构造方法
【Java】继承、super、final、子类构造方法
26 0
|
1月前
|
安全 Java 编译器
了解final关键字在Java并发编程领域的作用吗?
【10月更文挑战第8天】在Java并发编程中,`final`关键字具有重要作用,包括保证变量的可见性和不可变性,防止对象引用被意外修改,并帮助编译器优化读取操作及消除不必要的同步。通过确保变量不可变,`final`增强了多线程环境下的安全性与性能。
|
3月前
|
前端开发 JavaScript Java
【前端学java】java中final修饰符(6)
【8月更文挑战第9天】java中final修饰符(6)
38 2
|
3月前
|
Java Android开发
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
478 1