目录
final关键字定义与作用
在java中,关键字用于确保其修饰的类、方法或变量不可被改变。具体来说:
-
修饰变量:当一个变量被声明为
final
时,意味着这个变量的值在初始化后就不能被修改。这包括成员变量(类变量和实例变量)、局部变量和形参。final
变量必须在声明时或构造函数中初始化,之后就不能再被赋值。 -
修饰方法:如果一个方法被声明为
final
,那么这个方法就不能被子类重写。这通常用于那些在父类中已经实现了最终逻辑,不希望子类修改的方法。 -
修饰类:当一个类被声明为
final
,那么这个类就不能被继承。这通常用于那些设计为不应该被修改或扩展的类,如Java中的String
类。
使用final
关键字的作用包括:
- 提高安全性:通过防止变量、方法和类的继承或重写,确保代码的稳定性和正确性。
- 优化性能:编译器可以对
final
变量进行优化处理,如直接替换常量值到代码中,减少运行时的开销。 - 增强代码可读性和可维护性:通过明确标识不应被修改的元素,使代码更易于理解和维护。
总之,final
关键字是Java中一个重要的工具,用于确保代码的安全性和稳定性,同时也提高了代码的可读性和可维护性。
修饰变量
修饰成员变量
当我们使用final修饰变量时,必须赋予初始值。指定初始值的地方如下:
- 类变量:必须在静态初始化块中指定初始值或声明该类变量时指定初始值,而且只能在这两个地方的其中之一指定。
- 成员变量:必须在普通初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定。
public class Class1 {
// 定义成员变量时直接赋值
final int a=0;
final String b;
final int c;
final static double d;
//对于被final修饰的没有初始值的类变量,必须在静态初始化代码块中赋值
static {
d=0.1;
}
//被final修饰的没有初始值的成员变量可以在初始化代码块中赋值
{
b="acd";
}
//被final修饰的没有初始值的成员变量还可以在构造函数中赋值
public Class1(int c) {
// b c 在之前都已经被赋值过了,因此,构造函数中无法对这两个数据进行操作
this.c = c;
}
}
修饰局部变量
系统不会对局部变量进行初始化,局部变量必须被显示初始化。因此使用final修饰局部变量时,即可以在定义时指定默认值,也可以不指定默认值。如果在定义时没有指定默认值,则可以在后面代码中对该final变量赋初始值,但只能一次,不能重复赋值;如果在定义时已经指定默认值,则后面代码中不能再对该变量赋值。
public static void main(String[] args) {
final int a=10;
final double b;
b=10;
b=11;
System.out.println(b);
}
运行结果:
会报错,b第一次赋值之后就不可以继续赋值了。
修饰基本类型变量和引用类型变量的区别
当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,final只保证这个引用变量所引用的地址不会改变,即一直引用同一个对象,但可以改变引用类型变量所引用的对象的内容。
class Cat{
private String name;
public Cat(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Class2 {
public static void main(String[] args) {
// 创建了3个对象,一个数组对象一个int,一个自定义的cat
// 其中 数组和cat时引用类型,而int是基本类型
final int [] arr=new int[]{1,2,3,4,5};
final int a=10;
final Cat cat=new Cat("mimi");
System.out.println(Arrays.toString(arr));
System.out.println(cat.getName());
arr[3]=10;
cat.setName("huahua");
System.out.println(Arrays.toString(arr));
System.out.println(cat.getName());
}
}
运行结果:
修饰方法
final修饰的方法不可被重写,如果出于某些原因,不希望子类重写父类某个方法,则可以使用final修饰该方法。Java提供的Object类里就有一个final方法:getClass(),因为Java不希望任何类重写这个方法,所以使用final把这个方法密封起来。但对于该类提供的toStirng()和equals()方法,都允许子类重写,因此没有使用final修饰他们。
修饰类
final修饰的类不可以有子类,例如java.lang.String类就是一个final类,他不可以有子类。
当子类继承父类时,将可以访问到父类内部数据,并可以通过重写父类方法来改变父类方法的实现细节,这可能导致一些不安全的因素。为了保证某个类不可被继承,则可以使用final修饰这个类。
因此抽象类肯定就不可能被final修饰,不然一点意义没有,直接用final修饰,会直接报错。