基本定义
final是java中的一个关键字,它主要用于修饰类,方法和变量。
final类
当你不希望某个类被继承时,可以将其声明为final,这会是这个类无法被继承。
虽然final类无法被继承,但仍可以被实例化。
public class go {
public static void main(String[] args) {
A a = new A();//对A类进行实例化
}
}
final class A {//将A类声明为final
}
class B extends A{//错误,A类无法被继承
}
final方法
当你不希望父类中的某个方法被子类覆盖/重写(Override)时,可以使用final关键字修饰。
class A {//定义父类A类
public final void show(){}//定义final方法show
}
class B extends A{//定义子类B类
@Override//尝试重写show方法
public void show() {//错误,show方法无法被覆盖/重写
super.show();
}
}
如果类不是final类,但是含有final方法,则该方法虽然不能被重写,但能被继承。
public class go {
public static void main(String[] args) {
new B().show();
//可通过B类调用show方法,证明可继承父类fianal方法
}
}
class A {//父类A类
public final void show(){//final方法
}
}
class B extends A{//子类B类
}
final变量
常量
当final修饰了一个变量之后,这个变量的值在初始化之后就不能再改变,也就变成了一个常量。(常量命名时通常全部大写,中间用下划线“_”连接,以表示其值不可变性)
class A {
public int num1=0;//定义变量num1
//用final修饰变量NUM2,也称常量
public final int NUM2=0;
}
局部常量
局部常量是在方法、构造函数、初始化块或任何代码块内部声明的final变量。它的作用域被限制在其被声明的代码块内,一旦初始化后,其值就不能被改变。
class A {
public void show() {
// 这是一个局部常量
final int NUM = 10;
// 在这个方法内部,你可以使用 NUM,但不能修改它
System.out.println("The value of NUM is: " + NUM);
// 下面的代码会导致编译错误,因为局部常量不能被重新赋值
NUM = 20; // 错误!final变量不能被重新赋值
}
public static void main(String[] args) {
A demo = new A();
demo.show(); // 输出:The value of LOCAL_CONSTANT is: 10
// 下面的代码会导致编译错误,因为NUM只在show方法内部可见
System.out.println(NUM); // 错误!NUM在此作用域中不可见
}
}
全局常量(类的静态常量)
虽然Java中并没有严格意义上的“全局”常量(因为Java中没有全局变量概念),但通常我们将类的静态常量视作全局常量,因为它们可以在整个程序中访问。
在Java中,全局常量通常是以 public static final 声明的变量。这样的常量在整个程序中都是可见的,而且其值在程序运行期间是不可变的。全局常量常常用于定义一些不会改变的配置信息或标准值。
class A {
//这是一个全局变量
public static final int NUM=0;
}
常量赋值
final修饰的属性在定义时,必须赋值,且之后就不可再修改,赋值可以在以下三个位置进行:
- 定义时直接赋值
- 在构造器中赋值
- 在代码块中赋值
class A {
public final int NUM1=0;//直接赋值
public final int NUM2; //创建时不赋值
public A(int NUM2) { //通过构造函数赋值
this.NUM2 = NUM2;
}
public final int NUM3;//创建时不赋值
{//通过代码块赋值
NUM3=0;
}
}
如果final修饰的属性时静态的,即全局常量时,其不能在构造器中赋值,只能通过定义时直接赋值和在代码块中赋值两种方法赋值。
因为静态属性在类加载时就已创建,而构造器是在创建类时才会被调用,所以如果使用构造器赋值会导致静态常量已存在,内部却为空的情况。
注意事项
1、一般来说,如果类为final类,那么其中的方法就没必要再用final修饰。
2、final不能修饰构造方法(即构造器)
3、final往往和static搭配使用,效率更高
当我们仅使用static声明变量时,调用该变量会导致该变量所在类被加载,这无疑会占用更多的系统资源:
public class go {
public static void main(String[] args) {
System.out.println(A.NUM);//调用NUM
}
}
class A {
public static int NUM=100;//定义静态变量
static {
System.out.println("静态代码块被执行");
}
}
执行结果:
静态代码块被执行
100
而如果将final和static搭配使用,系统则不会加载A类,这样会使系统的运行效率提高:
public class go {
public static void main(String[] args) {
System.out.println(A.NUM);//调用NUM
}
}
class A {
public final static int NUM=100;//定义常量
static {
System.out.println("静态代码块被执行");
}
}
执行结果:
100
final和static的顺序无强制要求,但为便于理解,我们习惯将final写在前面。
4、包装类(如double,float,Boolean等),String都是fianl类:
//String.java中String类
public final class String{.....}