final关键字的引入:
由于在继承中,方法有一个现象:方法重写
所以,父类的功能就会被子类给覆盖掉
但是,有些时候,我们不想让子类覆盖掉父类的功能,只让他使用
这个时候,针对这种情况,Java就提供了一个关键字:final
举例:
1 class Fu { 2 public void show() { 3 System.out.println("hello Fu"); 4 } 5 } 6 class Zi extends Fu { 7 public void show() { 8 System.out.println("hello Zi"); 9 } 10 } 11 public class FinalTest { 12 public static void main(String[] args) { 13 Zi zi = new Zi(); 14 zi.show(); 15 } 16 }
输出:
hello Zi
案例2:
1 class Fu { 2 public final void show() { 3 System.out.println("hello Fu"); 4 } 5 } 6 class Zi extends Fu { 7 //编译报错,Zi中的show无法覆盖Fu中的show,被覆盖的方法为final 8 public void show() { 9 System.out.println("hello Zi"); 10 } 11 } 12 public class FinalTest { 13 public static void main(String[] args) { 14 Zi zi = new Zi(); 15 zi.show(); 16 } 17 }
final关键字的特点:
final可以修饰:类,方法,变量
被final修饰的类,不能被任何类继承
1 final class Fu { 2 public void show() { 3 System.out.println("hello Fu"); 4 } 5 } 6 class Zi extends Fu { //编译报错,无法从最终Fu进行继承 7 public void show() { 8 System.out.println("hello Zi"); 9 } 10 } 11 public class FinalTest { 12 public static void main(String[] args) { 13 Zi zi = new Zi(); 14 zi.show(); 15 } 16 }
被final修饰的方法是不能被重写的(见案例2)
被final修饰的变量是不能被重新赋值
此时的变量相当于常量(自定义常量) public final int num2 = 20;
常量分为:字面值常量和自定义常量
1 class Fu { 2 public int num = 10; 3 public final int num2 = 20; 4 } 5 class Zi extends Fu { 6 public void show() { 7 System.out.println(num); 8 System.out.println(num2); 9 10 num = 100; 11 num2 = 200; //编译时报错,无法为最终变量num2分配值 12 System.out.println(num); 13 System.out.println(num2); 14 } 15 }
final关键字修饰局部变量:
1. 权限修饰符修饰变量是没有意义的,因为局部变量本身就是被封装到方法中,外界无法访问的,但是final却可以修饰局部变量。
之前讲解的是final修饰成员变量的情况,那么final修饰局部变量是什么情况呢?
1.在方法内部,该变量不可以被改变
当局部变量是基本数据类型的时候,值不能被改变
当局部变量是引用数据类型的时候,指的是地址值不能被改变,在堆内存中存放的值是可以被改变的
案例4
1 public static void main(String[] args) { 2 //局部变量是基本数据类型 3 int num = 10; 4 final int num2 = 20; 5 6 System.out.println(num); 7 System.out.println(num2); 8 9 num = 100; 10 //num2 = 200; //编译时报错,无法为最终变量num2分配值 11 System.out.println(num); 12 System.out.println(num2); 13 }
输出:
10 20 100 20
class Fu { int age = 10; } public class FinalTest { public static void main(String[] args) { //局部变量是引用数据类型 Fu fu = new Fu(); System.out.println(fu.age); fu.age = 100; System.out.println(fu.age); final Fu fu2 = new Fu(); System.out.println(fu2.age); fu2.age = 300; System.out.println(fu2.age); } }
输出:
10 100 10 300
案例5
1 class Fu { 2 int age = 10; 3 } 4 5 public class FinalTest { 6 public static void main(String[] args) { 7 8 Fu fu = new Fu(); 9 System.out.println(fu.age); //10 10 11 Fu fu2 = new Fu(); 12 fu2.age = 50; 13 System.out.println(fu2.age); //50 14 15 fu = fu2; 16 System.out.println(fu.age); //50 17 18 } 19 }
输出结果:
10 50 50
案例6
1 public static void main(String[] args) { 2 final Fu fu = new Fu(); 3 System.out.println(fu.age); //10 4 5 Fu fu2 = new Fu(); 6 fu2.age = 50; 7 System.out.println(fu2.age); //50 8 9 fu = fu2; //编译时报错,无法为最终变量fu分配值 10 System.out.println(fu.age); 11 }
final修饰变量的初始化时机
1. 被final修饰的变量只能被赋值一次(不包括系统给出的默认值)
2.在构造方法完毕前(针对非静态常量)
变量在初始化时先进行成员变量初始化,再进行构造方法初始化
//变量初始化时,先进行局部变量初始化,再进行成员变量初始化 class Fu { int num = 100; public Fu(){ num = 200; } } public class FinalTest { public static void main(String[] args) { Fu fu = new Fu(); System.out.println(fu.num); //200 } }
输出:
200
final修饰变量的初始化时机:在对象构造完毕前即可。
1 class Fu { 2 final int num = 100; 3 4 public Fu(){ 5 num = 200; //编译时报错,无法为最终变量num分配值 6 } 7 }
class Fu { final int num;//此时只有系统给出的默认值 public Fu(){ num = 200; } } public class FinalTest { public static void main(String[] args) { Fu fu = new Fu(); System.out.println(fu.num); //200 } }
输出:
200
class Fu { final int num; { num = 500; //先走构造代码块赋值,再走构造方法赋值 } public Fu(){ num = 200; //编译时报错,无法为最终变量num分配值 } }