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成员变量表示常量,只能被赋值一次,赋值后的值不能改变。