final可以修饰非抽象类、非抽象类成员方法和变量。
(1)final类:不能被继承,没有子类,final类中的方法默认是final的;
(2)final方法:不能被子类的方法覆盖,但可以被继承;
(3)final成员变量:表示常量,只能被赋值一次,赋值后值不再改变;
(4)final不能用于修饰构造方法。
(父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final的)
1.final类
final类不能被继承,因此final类的成员方法没有机会被覆盖,默认是final的,在设计类的时候,如果这个类不需要有子类,类的实现细节不允许变动,并且确定这个类不会再被扩展,可以将这个类设置为final类。
2.final方法
如果一个类不允许子类覆盖某个方法,可以将这个方法设置为final方法。
将方法声明为final的原因主要有两个:
①将方法锁定:防止任何子类修改它的意义和实现;
②高效:编译器遇到调用final方法的时候,会转入内嵌机制,大大提高执行效率。
父类Test1.java
package EmployeeTest_4_2; public class Test1 { public static void main(String[] args) { } public void f1() { System.out.println("父类的f1"); } public final void f2() { System.out.println("父类的f2"); } public void f3() { System.out.println("父类的f3"); } public void f4() { System.out.println("父类的f4"); } }
子类Test2.java
package EmployeeTest_4_2; public class Test2 extends Test1 { public void f1() { System.out.println("父类的f1方法被覆盖!"); } //这种声明f2的方法会报错,因为在Test1中已经将f2方法声明为final // public void f2() // { // System.out.println("父类的f2方法被覆盖!"); // } public void f3() { System.out.println("父类的f3方法被覆盖!"); } public static void main(String[] args) { Test2 t = new Test2(); t.f1(); t.f2(); t.f3(); t.f4(); } }
输出的结果为:
父类的f1方法被覆盖! 父类的f2 父类的f3方法被覆盖! 父类的f4
由于父类中f2方法已经被声明为final,所以如果在子类Test2中重写f2方法的时候,会报错,这时候会提示将父类Test1中的f2方法声明为“非final”方法。
Exception in thread "main" java.lang.VerifyError: class EmployeeTest_4_2.Test2 overrides final method f2.()V at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(Unknown Source) at java.security.SecureClassLoader.defineClass(Unknown Source) at java.net.URLClassLoader.defineClass(Unknown Source) at java.net.URLClassLoader.access$100(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
3.final变量
用final修饰的成员变量表示常量,值一旦给定就无法改变。
总共可以修饰三种变量:静态变量、实例变量和局部变量。
final变量定义的时候,可以先声明,而不给初值,这中变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初始化。但是,final空白在final关键字final的使用上提供了更大的灵活性,为此,一个类中的final数据成员就可以实现依对象而有所不同,却有保持其恒定不变的特征。
package EmployeeTest_4_2;
public class Test3
{
private final String s = "final变量";
private final int A = 100;
public final int B = 90;
public static final int C = 80;
public static final int D = 70;
public final int E;//final空白,必须在初始化对象的时候赋初值
public Test3(int x)
{
E = x;
}
public static void main(String[] args)
{
Test3 t = new Test3(2);
// t.A = 101;//final变量的值一旦给定就无法改变
// t.B = 91;
// t.C = 81;
// t.D = 71;
System.out.println(t.A);
System.out.println(t.B);
System.out.println(t.C); //不推荐用对象方式访问静态字段
System.out.println(t.D);
System.out.println(Test3.C);
System.out.println(Test3.D);
//System.out.println(Test3.E);//出错,因为E为final空白,依据不同对象值有所不同.
System.out.println(t.E);
Test3 t1 = new Test3(3);
System.out.println(t1.E);//final空白变量E依据对象的不同而不同
}
private void test()
{
System.out.println(new Test3(1).A);
System.out.println(Test3.C);
System.out.println(Test3.D);
}
public void test2()
{
final int a;//final空白,在需要的时候才赋值
final int b = 4;//局部常量--final用于局部变量的情形
final int c;//final空白,一直没有给赋值.
a = 3;
//a=4; 出错,已经给赋过值了.
//b=2; 出错,已经给赋过值了.
}
}
输出结果:
100
90
80
70
80
70
2
3
4. final参数
当函数参数为final类型的时候,可以读取使用该参数,但是无法修改该参数的值。
package EmployeeTest_4_2; public class Test4 { public static void main(String[] args) { new Test4().f1(1); } public void f1(final int i) { System.out.println(i); } }
总结:
1、final修饰类
final修饰的类不允许被继承。一个类不能既是final的,又是abstract的,因为抽象类的目的就是为了让子类去实现其中的方法,而final修饰的类不能被继承,所以产生了矛盾。
2、final修饰方法
final修饰方法,表示该方法不能被子类重写Override。
3、final修饰变量
final成员变量表示常量,只能被赋值一次,赋值后的值不能改变。