Final在Java中是final的意思,也可以称为终结器,表示对象处于最终形式,无法更改。 Final应用于类、方法、变量时含义有所不同,但本质是一样的。 它们都表示不可更改,类似于C#中的关键字。
使用final关键字声明类、变量和方法时,需要注意以下几点:
最终修改变量
被final修饰的变量成为常量,只能赋值一次,但是被final修饰的局部变量和成员变量不同。
用final修饰的局部变量必须先赋值后才能使用。 声明时未赋值的最终修饰的成员变量称为“空白最终变量”。 空的最终变量必须在构造函数或静态代码块中初始化。
注意:被final修饰的变量不能赋值的说法是错误的。 严格来说,被final修饰的变量是不能被改变的。 一旦获得初始值,最终变量的值就不能重新分配。
public class FinalDemo {
void doSomething() {
// 没有在声明的同时赋值
final int e;
// 只能赋值一次
e = 100;
System.out.print(e);
// 声明的同时赋值
final int f = 200;
}
// 实例常量
final int a = 5; // 直接赋值
final int b; // 空白final变量
// 静态常量
final static int c = 12;// 直接赋值
final static int d; // 空白final变量
// 静态代码块
static {
// 初始化静态变量
d = 32;
}
// 构造方法
FinalDemo() {
// 初始化实例变量
b = 3;
// 第二次赋值,会发生编译错误
// b = 4;
}
}
上述代码的第 4 行和第 6 行声明了局部常量。 第4行只是声明没有赋值,但使用前必须赋值(见代码第6行)。 事实上,最好在声明局部常量的同时对其进行初始化。
代码的第13、14、16、17行都声明了成员常量。 代码的第 13 行和第 14 行是实例常量。 如果是空白的final变量(参见代码第14行),则需要在构造函数中对其进行初始化(参见代码第27行)。
代码第16行和第17行是静态常量。 如果是空白的final变量(参见代码第17行),则需要在静态代码块中对其进行初始化(参见代码第21行)。
另外,无论哪种常量都只能赋值一次,参见代码第29行给b常量赋值。 因为b之前已经赋值过一次,所以这里会出现编译错误。
Final修饰的基本类型变量和引用类型变量的区别
当使用final修饰基本类型变量时,基本类型变量不能被重新赋值,因此基本类型变量不能被改变。 但对于引用类型变量来说,它只保存一个引用。 Final只是保证这个引用类型变量引用的地址不会改变,即它总是引用同一个对象,但这个对象可以完全改变。
下面的程序演示了final如何修改数组和对象。
import java.util.Arrays;
class Person {
private int age;
public Person() {
}
// 有参数的构造器
public Person(int age) {
this.age = age;
}
// 省略age的setter和getter方法
// age 的 setter 和 getter 方法
}
public class FinalReferenceTest {
public static void main(String[] args) {
// final修饰数组变量,iArr是一个引用变量
final int[] iArr = { 5, 6, 12, 9 };
System.out.println(Arrays.toString(iArr));
// 对数组元素进行排序,合法
Arrays.sort(iArr);
System.out.println(Arrays.toString(iArr));
// 对数组元素赋值,合法
iArr[2] = -8;
System.out.println(Arrays.toString(iArr));
// 下面语句对iArr重新赋值,非法
// iArr = null;
// final修饰Person变量,p是一个引用变量
final Person p = new Person(45);
// 改变Person对象的age实例变量,合法
p.setAge(23);
System.out.println(p.getAge());
// 下面语句对P重新赋值,非法
// p = null;
}
}
从上面的程序可以看出,用final修饰的引用类型变量是不能重新赋值的,但是引用类型变量所引用的对象的内容是可以改变的。
例如,在上面的iArr变量引用的数组对象中,最终修改的iArr变量无法重新赋值,但iArr引用的数组的数组元素可以更改。
同样,p变量也用final修饰,表示p变量不能重新赋值,但可以改变p变量引用的对象的成员变量的值。
注意:使用final声明变量时,要求所有字母均为大写,如SEX。 这在开发中非常重要。
如果程序中的变量被声明为final,则该变量将被称为全局变量,如下代码所示:
public static final String SEX= "女";
最终修改方法
用final修饰的方法不能被覆盖。 如果由于某种原因,不希望子类重写父类的某个方法,可以使用final修饰该方法。
Java提供的类中有一个final方法()。 因为Java不希望任何类重写这个方法,所以它使用final来密封这个方法。 但子类允许重写本类提供的()和()方法,因此不被final修饰。
下面的程序尝试重写final方法,这将导致编译错误。
public class FinalMethodTest {
public final void test() {
}
}
class Sub extends FinalMethodTest {
// 下面方法定义将出现编译错误,不能重写final方法
public void test() {
}
}
上面程序中的父类是,该类中定义的test()方法是final方法。 如果其子类尝试重写此方法,则会发生编译错误。
对于一个方法,由于它只在当前类中可见,所以它的子类无法访问该方法,因此子类无法重写该方法——如果子类定义了与父类具有相同方法名和相同形参列表的方法 ,具有相同返回值类型的方法不是方法重写,而只是重新定义一个新方法。
因此,即使使用final修饰一个访问权限方法,仍然可以定义与其子类中的方法具有相同方法名、相同形参列表、相同返回值类型的方法。
下面的程序演示了如何在子类中“重写”父类的final方法。
public class PrivateFinalMethodTest {
private final void test() {
}
}
class Sub extends PrivateFinalMethodTest {
// 下面的方法定义不会出现问题
public void test() {
}
}
上面的程序没有问题。 虽然子类和父类也包含同名的void test()方法,但是子类并没有重写父类的方法,所以即使父类的void test()方法被final修饰, void test() 方法仍然可以在子类中定义。
最终修改的方法只是不能被重写,不能重载,所以下面的程序是没有问题的。
public class FinalOverload {
// final 修饰的方法只是不能被重写,完全可以被重载
public final void test(){}
public final void test(String arg){}
}
最终修改类
Final修饰的类不能被继承。 当子类继承父类时,它将能够访问父类的内部数据,并通过重写父类方法来改变父类方法的实现细节,这可能会导致一些不安全因素。 为了保证某个类不能被继承,可以使用final来修饰这个类。
下面的代码演示了final修饰的类不能被继承。
final class SuperClass {
}
class SubClass extends SuperClass { //编译错误
}
因为该类是final类,尝试从该类继承将导致编译错误。
Final修饰符用法总结
1.final修改类中的变量
这意味着变量一旦初始化就无法更改。 这里不可变的意思是,对于基本类型变量来说,它的值是不可变的,而对于对象引用类型变量来说,它的引用不能再改变。
它的初始化可以在两个地方:
一是它的定义,也就是说定义的时候直接给final变量赋值;
二是在施工方法上。
这两个地方只能选其一,要么在定义的时候给一个值,要么在构造函数中给一个值。 您不能在定义时分配一个值,并同时在构造函数中分配另一个值。
2、类中final修饰的方法
表示该方法提供的功能已经满足当前需求,不需要扩展,并且任何继承该类的类都不允许重写该方法,但继承仍然可以继承该方法,也就是说可以可以直接使用。
在声明类中,final 方法仅实现一次。
3.最终修改类
表示这个类不能被任何其他类继承,也就是说这个类是继承树中的叶类,并且这个类的设计已经认为是完美的,不需要修改或扩展。
对于最终类中的成员,您可以将它们定义为最终类或非最终类。 至于方法,既然所属的类是final的,那么它们自然就成为了final。 你也可以显式地给final类中的方法添加一个final,这显然是没有意义的。
Java 入门的基本视频教程。 如果你是Java零基础自学,选择黑马程序员的Java入门教程(含Java项目和Java真题)