java的學習:final關鍵字

final,見名知意,就是最終的意思,那麼它在java中可以修飾什麼呢?又有什麼作用呢?

一、final的使用

在java中,final可以修飾變量,方法,類。

1.1 final修飾變量

當變量被final修飾時,那麼此時的變量也就稱之爲常量。當一旦final修飾的變量被初始化後,那麼值(數值和引用地址值)將不能再被改變。

1.1.1 final修飾成員變量

當final修飾成員變量時,必須要顯式初始化,也就是你必須要給它賦個值。
在這裏插入圖片描述
那麼有哪些方式可以賦值呢?

1.1.1.1 成員變量爲基本類型時

當成員變量爲基本類型時,那麼此時被final修飾的它們,一旦初始化後,數值將不可改變。

public class Demo {
    public static void main(String[] args) {
        Box b1=new Box();
        System.out.println(b1);
        System.out.println("=================");
        Box b2=new Box(20);
        System.out.println(b2);
    }
}

class Box{
    //Variable 'length' might not have been initialized
    //final int length;
    //一般對於常量,我們都全大寫表示,爲了演示方便,就不用了
    //final int LENGTH=0;

    final int length=5;  //聲明時初始化
    final int width;     //代碼塊中初始化
    final int height;    //構造器初始化

    {
        //Cannot assign a value to final variable 'length':不能將值賦給最終變量length
        //length=10;
    }

    //代碼塊初始化
    {
        width=10;
    }

    public Box() {
        this.height = 15;
    }

    public Box(int height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Box{" +
                "length=" + length +
                ", width=" + width +
                ", height=" + height +
                '}';
    }
}

輸出:

Box{length=5, width=10, height=15}
=================
Box{length=5, width=10, height=20}

通過上例代碼,我們可以發現,當成員變量被final修飾時,我們可以通過聲明初始化,代碼塊,構造器,爲final修飾的成員變量進行賦值初始化操作,而在初始化後值將不能再改變

1.1.1.2 成員變量爲引用類型
class Duck{
    private String name;

    public Duck() {
    }

    public Duck(String name) {
        this.name = name;
    }
}

class Dog {
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    //getter方法
    public String getName() {
        return name;
    }
}

class Cat {
    private String name;

    public Cat(String name) {
        this.name = name;
    }

    //getter方法
    public String getName() {
        return name;
    }
}

class Mouse {
    private String name;

    public Mouse(String name) {
        this.name = name;
    }

    //getter和setter方法
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Box {
    Duck duck=new Duck();
    final Dog dog = new Dog("Speike");  //聲明初始化
    final Cat cat;       //代碼塊初始化
    final Mouse mouse;   //構造器初始化

    //代碼塊初始化
    {
        cat = new Cat("Tom");
    }

    //代碼塊初始化
    {
        duck=new Duck("唐老鴨");
        //Variable 'dog' might already have been assigned to
        //dog = new Dog("大黃");  //編譯不通過
    }

    //無參構造初始化
    public Box() {
        mouse = new Mouse("Jerry");
    }

    //有參構造初始化
    public Box(Mouse mouse) {
        this.mouse = mouse;
    }

    @Override
    public String toString() {
        return "Box{" +
                "dog地址值:" + System.identityHashCode(dog) +
                ",dog值:" + dog.getName() +
                ", cat地址值:" + System.identityHashCode(cat) +
                ", cat值:" + cat.getName() +
                ", mouse地址值:" + System.identityHashCode(mouse) +
                ", mouse值:" + mouse.getName() +
                '}';
    }
}

public class Demo {
    public static void main(String[] args) {

        Box box=new Box();
        System.out.println(box);
        System.out.println("========================================分割線==============================================");

        Mouse mouse = new Mouse("米老鼠");
        Box b1 = new Box(mouse);
        System.out.println("修改前:"+b1);
        //修改mouse的值
        mouse.setName("傑瑞");
        System.out.println("修改後:"+b1);



    }
}

輸出:

Box{dog地址值:460141958,dog值:Speike, cat地址值:1163157884, cat值:Tom, mouse地址值:1956725890, mouse值:Jerry}
========================================分割線==============================================
修改前:Box{dog地址值:356573597,dog值:Speike, cat地址值:1735600054, cat值:Tom, mouse地址值:21685669, mouse值:米老鼠}
修改後:Box{dog地址值:356573597,dog值:Speike, cat地址值:1735600054, cat值:Tom, mouse地址值:21685669, mouse值:傑瑞}

在上例中,我們在Box中初始化無final修飾的Duck和有final修飾的Dog,Cat,Mouse。通過比較我們可以發現,final修飾的引用類型的成員變量亦是可以通過聲明,代碼塊,構造器進行初始化,並且比較Duck和Dog後,還可以發現,final修飾的引用類型的成員變量在第一次初始化後,不可以被再次賦值,而Duck沒被final修飾,則沒有此限制。
接着我們在main方法中創建了一個mouse對象和b1對象,然後我們打印了下b1對象,接下了我們修改了mouse的name值,接着再次進行打印。比較一下修改前後的打印的值,發現在將mouse值由米老鼠修改成傑瑞時,他們的mouse對象的地址值並沒有改變。由此我們可以確認,final修飾引用類型的成員變量時,在將它們初始化後,將不能再指向其他對象,但它們所指向對象的內容卻是可以修改的。

1.1.2 final修飾局部變量

當使用final修飾局部變量時,在初始化後,將不可給它們再次賦值,也就是說,在第一次賦值後,它們的值(無論是數值還是地址值)都將不能改變。

1.1.2.1 局部變量類型爲基本類型
public class Demo{
    public static void main(String[] args) {
        Box box=new Box();
        box.show(10);
    }
}

class Box{

    public void info(){
        final int ID=10;
        //ID=10; //Cannot assign a value to final variable 'ID'
    }

    public void show(final int price){
        //Cannot assign a value to final variable 'price'
        //price=10;
        System.out.println(price);
    }

}

輸出:

10

通過上例,我們可以發現在final修飾基本類型的局部變量(參數列表也是局部變量)時,數值在第一次賦值後將不能再被改變。

1.1.2.2 局部變量類型爲引用類型
class Box {

    public void info() {
        final Gift gift=new Gift();
        //Cannot assign a value to final variable 'gift'
        //gift=new Gift();
    }

    public void showFinal(final Gift gift){
        //Cannot assign a value to final variable 'gift'
        //gift=new Gift();
        System.out.println(gift);
    }

    public void show(Gift gift){
        gift=new Gift();
        System.out.println(gift);
    }

}

在上例,final修飾的引用類型的局部變量在初始化後,會發現不能改變它們指向的引用地址值了。

1.2 final修飾方法

當方法被final所修飾時,那麼這個方法不能被重寫(覆蓋)

class Animal{

    final void info(){

    }
}

class Cat extends Animal{

    //'info()'cannot override 'info()'in 'Animal';overridden method is final
    //info()方法不能被重寫
//    void info() {
//        super.info();
//    }
    
}

1.3 final修飾類

當類被final所修飾時,那麼這個不會被其他類所繼承

public class Demo {
    public static void main(String[] args) {
        Animal cat=new Animal();
        cat.name="Tom";
        cat.info();
    }
}

final class Animal{
    String name;
    final int age=1;

    void info(){
        System.out.println(name+":"+age+"歲");
    }
}
//Cannot inherit from final 'Animal'  //無法繼承最終類A
//class Cat extends Animal{
//
//}

輸出:

Tom:1

上述代碼中,當類Animal被final修飾後,Cat類將不可以繼承Animal類,這時編譯是不會通過的,理所當然的,既然類不能被繼承,那麼類中的方法自然也不會被重寫(覆蓋)。對於屬性name,age可以發現在最終類Animal中,屬性可以爲final所修飾,也可以不被final修飾。

在java中也有許多類被final修飾,比如說:String類,System類等等。它們都不能被繼承。
在這裏插入圖片描述

二、總結

通過以上可以總結出:
final可以修飾變量,方法,類
final修飾變量時,此時的變量被稱爲常量。當變量經過初始化後,它們的數值或者引用地址值是不能再次改變的。

  • final修飾成員變量:成員變量爲基本數據類型時,在初始化後,就不能改變數值了。成員變量爲引用數據類型時,在初始化後,成員變量就不能指向其他的對象了。對於初始化,成員變量可以通過聲明初始化,代碼塊初始化,構造器初始化三種方式
  • final修飾局部變量:局部變量在初始化後,它的數值或引用地址值將不能改變。

final修飾方法:當方法被final修飾時,將不能被重寫。
final修飾類:當類被final修飾時,將不能被繼承,而由此方法也必定不會被重寫

最後:static關鍵字可以和final連用。可以用來修飾屬性和方法()。
當修飾屬性時,此時變量爲全局常量,並且它在類的加載時就會初始化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章