當final作用於變量、參數、方法和類時該如何處理


final變量:

  對於基本類型使用final:它就是一個常量,數值恆定不變

 

  對於對象引用使用final:使得引用恆定不變,一旦引用被初始化指向一個對象,就無法再把 它改為指向另一個對象。然而,對象自身卻是可以被修改的,java並沒有提供使任何對象恆定不變的途徑。這一限制同樣也使用數組,它也是對象。

例子:

 

class Value{
    int i;
    public Value(int i){
        this.i = i;
    }
}

public class FinalData {
    private static Random random = new Random(47);
    private String id;
    
    public FinalData(String id){
        this.id = id;
    }
    
    private final int valueOne = 9;
    private static final int VALUE_TWO = 99;
    public static final int VALUE_THREE = 39;
    private final int i4 = random.nextInt(20);
    static final int INT_5 = random.nextInt(20);
    
    private Value v1 = new Value(11);
    private final Value v2 = new Value(22);
    private static final Value VAL_3 = new Value(33);
    
    private final int[] a = {1, 2, 3, 4, 5, 6};
    public String toString(){
        return id + ": " + "i4 = " + i4 + ", INT_5 = " + INT_5;
    }
    
        public static void main(String[] args) {
        FinalData fd1 = new FinalData("fd1");
        //! fd1.valueOne++; // 因為valueOne是基本類型常量,其數值恆定不變
        fd1.v2.i++; //final修飾的對象的內容可以改變
        fd1.v1 = new Value(9);
        for(int i = 0; i < fd1.a.length; i++)
            fd1.a[i]++;
        //! fd1.v2 = new Value(0); // 因為v2是final修飾的引用類型,其引用不能被修改指向另一個對象
        //! fd1.VAL_3 = new Value(1); // 表示占據一段不能改變的內存空間
        //! fd1.a = new int[3]; // final修飾的數組
        System.out.println(fd1);
        System.out.println("Creating new FinalData");
        FinalData fd2 = new FinalData("fd2");
        System.out.println(fd1);
        System.out.println(fd2);
    }
}
/*output:
fd1: i4 = 15, INT_5 = 18
Creating new FinalData
fd1: i4 = 15, INT_5 = 18
fd2: i4 = 13, INT_5 = 18
*/    

 

分析:

  對於fd1fd2兩個對象,其中i4是唯一的,即每個對象都有一個i4,但INT_5被聲明為static,即是類共享的,fd1fd2共享INT_5,在裝載時已經被初始化,而不是每次創建新對象時初始化(例如i4);但它同時被設置成final,所以它的引用是不可改變的,即不能被修改指向另一個對象。

 

 

空白final

 

  被聲明為final但又沒有給定初值。必須在域的定義或者每個構造器中使用表達式對final進行賦值,這正是final域在使用前總是初始化的原因。

 

 

 

 

final參數:

  這意味着你無法在方法中更改參數引用,使其指向另一個參數,但可以修改final對象所指向的內容

例子:

class Gizmo{
    int i = 0;
    public void spin(){}
}

public class FinalArguments {
    void with(final Gizmo g){
        //! g = new Gizmo(); // 無法修改final修飾的引用,使它指向另一個對象
        g.i++;    // 但可以修改final對象所指向的內容
    }
    void without(Gizmo g){
        g = new Gizmo();
        g.spin();
    }
    
//    int g(final int i){
//        //! i++; //因為參數i是常量值
//    }
    
    int g(final int i){
        return i + 1;
    }
    
    public static void main(String[] args) {
        FinalArguments bf = new FinalArguments();
        bf.without(null);
        bf.with(null);
    }
}

分析:

  參數被聲明為final,若是基本參數,那它就是一個常量,不能被修改;若是一個引用變量,那么它就不能被修改指向另一個對象,但可以修改該引用所指對象的內容。

 

fianl方法:

使用原因:

  1. 把方法鎖定,以防任何繼承類修改它的含義,即該方法不會被繼承的類覆蓋
  2. 效率,若一個方法指明為final,那么就同意編譯器將針對該方法的所有調用轉為內嵌調用。

類中所有的private方法都隱式地指定為final,由於無法取用private方法,所以也就無法覆蓋它。可以對private方法添加final修飾詞,但這並不會給該方法帶來任何額外的意義。

例子:

class WithFinals{
    private final void f(){
        System.out.println("WithFinals.f()");
    }
    private void g(){
        System.out.println("OverridingPrivate.f()");
    }
}

class OverridingPrivate extends WithFinals{
    private final void f(){
        System.out.println("OverridingPrivate.f()");
    }
    private void g(){
        System.out.println("OverridingPrivate.g()");
    }
}

class OverridingPrivate2 extends OverridingPrivate{
    /*
     * 當使用Override注解強制使f()方法覆蓋父類的f()方法時,會報錯
     * 因為它不知道父類是否有該方法,對於g()方法來說,它只是生成了一個新的方法,
     * 並沒有覆蓋掉父類中的g()方法。
     */
    //@Override
    public final void f(){
        System.out.println("OverridingPrivate2.f()");
    }
    public void g(){
        System.out.println("OverridingPrivate2.g()");
    }
}

public class FinalOverridingIllusion{
    public static void main(String[] args) {
        OverridingPrivate2 op2 = new OverridingPrivate2();
        op2.f();
        op2.g();
        
        // 可以向上轉型
        OverridingPrivate op = op2;
        //! op.f(); // 父類中final方法對子類來說是不可見的
        //! op.g();
        WithFinals wf = op2;
        // wf.f();
        // wf.g();
    }
}
/*output:
OverridingPrivate2.f()
OverridingPrivate2.g()
*/

分析:

  覆蓋何時發生:

    1,子類中出現與父類完全一致的方法

    2. 子類可以通過向上轉型為父類,並調用父類中的那個方法

  若父類中某個方法被聲明為final或者private,那么這個方法對子類來說是不可見的,就算在子類中創建了與父類一模一樣的方法,這也是一個新的方法,而不是從父類中覆蓋的方法。

 

final類:

  即該類不能被繼承,不管是你還是別人,也就是這個類不需要做任何變動,也不需要任何子類,例如String類。

例子:

 

class SmallBrain{}

final class Dinosaur{
    int i = 7;
    int j = 1;
    SmallBrain x = new SmallBrain();
    void f(){}
}
// error: The type Further cannot subclass the final class Dinosaur
// Dinosaur類不能有子類
// class Further extends Dinosaur{}

public class Jurassic {
    public static void main(String[] args) {
        Dinosaur n = new Dinosaur();
        n.f();
        n.i = 40;
        n.j++;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM