在我们编写Java程序时总会根据需求将变量、方法、类设置成static(静态)或final(最终),熟练掌握final用法是必须的,现在我们就来详细了解final关键字!

一、final概述

概念:由字面可以了解,final有最终态,无法改变的意思。

使用目的:为了阻止改变与提高效率。

高效原因:Java内嵌机制,final方法会在编译的过程中利用内嵌机制进行inline优化。

inline优化是指:在编译的时候直接调用方法代码替换,也就是内嵌,而不是在运行时调用方法。

inline需要在编译的时候就知道最后要用哪个方法。

显然,非final是不行的。
非final方法可能在子类中被重写,由于可能出现多态的情况,编译器在编译阶段
并不能确定将来调用方法的对象的真正类型,也就无法确定到底调用哪个方法。)

修饰对象:

1、非抽象类,由于被final修饰的类是不能被继承的,而抽象类必须被继承才有意义。

2、非抽象方法,由于被final修饰的方法是不能被重写的,而抽象方法必须被重写才有意义。

3、变量或常量。

注意:

1、final不能修饰构造方法。

2、父类的private方法是不能被子类重写的,因为private方法默认是final的。

二、具体用法

1、修饰类

final类不能被继承,所有其成员与方法自然没有机会被覆盖,默认是final的。所以在将类设计成final类的时候,一定要特别慎重考虑,确定这个类不需要有子类,类实现不能被改变,类不能被扩展的时候才能用final修饰。

注:Java中String类就是一个final类。

2、修饰方法

如果一个类不允许其子类覆盖某个方法,则可以把这个方法用final修饰。

这样做的目的可在《Java编程思想》中查到:

“使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。”

public class Test1 {		
public static void main(String[] args) { 
    // TODO 自动生成方法存根 
} 
public void f1() { 
    System.out.println("f1"); 
} 
//无法被子类覆盖的方法 
public final void f2() { 
    System.out.println("f2"); 
} 
public void f3() { 
    System.out.println("f3"); 
} 
private void f4() { 
    System.out.println("f4"); 
} 
} 
public class Test2 extends Test1 { 
    
public void f1(){     
    System.out.println("Test1父类方法f1被覆盖!"); 
} 
public static void main(String[] args) { 
    Test2 t=new Test2(); 
    t.f1();    
    t.f2(); //调用从父类继承过来的final方法 
    t.f3(); //调用从父类继承过来的方法 
    //t.f4(); //调用失败,无法从父类继承获得 
} 
}



3、修饰变量(重点)

1、final修饰基本数据类型变量,则其数值一旦被初始化就不能被更改。

2、final修饰引用变量(如ObjectName obj = new ObjectName();中obj就是一个引用变量,指向堆内存中对象空间的首地址),则其初始化后就不能修改引用指向另一个对象。

public class Test2 { 		
        private final String S = "final实例变量S"; 
        private final int A = 100; 
        public final int B = 90; 

        public static final int C = 80; 
        private static final int D = 70; 

        public final int E; //final空白,必须在初始化对象的时候赋初值 

        public Test3(int x) { 
                E = x; 
        } 

        /** 
         * @param args 
         */ 
        public static void main(String[] args) { 
                Test3 t = new Test3(2); 
                //t.A=101;    //出错,final变量的值一旦给定就无法改变 
                //t.B=91; //出错,final变量的值一旦给定就无法改变 
                //t.C=81; //出错,final变量的值一旦给定就无法改变 
                //t.D=71; //出错,final变量的值一旦给定就无法改变 

                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; 出错,已经给赋过值了. 
        } 
}
四、修饰参数

当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。

public class Test3 { 		
        public static void main(String[] args) { 
                new Test4().f1(2); 
        } 

        public void f1(final int i) { 
                //i++;    //i是final类型的,值不允许改变的. 
                System.out.print(i); 
        } 
}





本文转载:CSDN博客