首頁 > 軟體

Java幾個重要的關鍵字詳析

2022-07-25 14:01:26

1.extends

  • 用於類繼承類,用法:class+子類名+extends+父類別名+{}
class Animal{}//父類別
class cat extends Animal{}//子類用extends實現繼承 

注意:一個類只能用extends關鍵字宣告繼承一個父類別

  • 用於介面繼承介面,用法:interface+介面名+extends+介面名+{}
interface Clippers {}
interface Warriors {}
interface Lakers extends Clippers,Warriors {}//介面類用extends關鍵字繼承其他介面(可多個)

注意:

  • 介面不能用extends宣告繼承別的
  • 介面只能用extends宣告繼承別的介面,且可以繼承多個介面
  • 當一個類用implements實現了一個介面時,不僅要實現該介面的方法,也要實現該介面繼承的介面的方法

2.implements

  • 用於宣告一個類實現了一個介面類,用法:class+類名+implements+介面名+{}
class Nets implements Clippers,Warriors{}//用implements關鍵字宣告實現了兩個介面類

注意:

  • 一個普通類可以implements關鍵字宣告實現多個介面,但必須實現所有介面中的所有方法
  • 抽象類實現介面,可以不用實現介面的方法(因為抽象類中可以有抽象方法)
  • 意義:可以用implements關鍵字宣告實現多個介面來實現類似多繼承

3.final

使用方法:

  • 修飾,使該類不能被繼承
  • 修飾方法,使該方法不能被子類重寫 (仍可以被繼承呼叫
  • 修飾屬性,使該屬性的值不能被修改(使為常數
  • 修飾區域性變數,使該變數不能被修改(區域性常數

使用細節:

final修飾的屬性在定義時必須賦初值,且不能修改,可以在以下位置賦初值

  • 定義時(顯示初始化)
  • 在構造器中
  • 在程式碼塊中

static final:全域性常數

  • 如果final修飾的屬性是靜態(static)的,則不能在構造器中賦初值,原因:靜態屬性要求在類載入時就有初值,而構造器在建立物件時才被呼叫,所以可能導致呼叫靜態屬性時沒有建立物件而沒有給靜態屬性賦值
  • final不能修飾構造方法,沒有意義
  • finalstatic同時修飾的屬性在呼叫時不會導致類的載入,效率更高

4.native

基本介紹:

native用來修飾方法,被修飾的方法即成為了一個Java呼叫但非Java程式碼實現的介面(本地方法) ,該方法在外部可以用任何語言去實現

"A native method is a java method whose implementation is provided by non-java code."

使用方法:

native修飾方法的位置必須在方法返回型別之前,和方法存取修飾符位置沒有要求,如:public native int hashCode();

native細節:

  • native方法沒有方法體,也沒有{}
  • native修飾後的方法不能用abstract修飾,因為abstract指明該方法無實現體,而native方法是有實現體的,只是用非Java程式碼實現的
  • native方法的返回型別可以是任意型別
  • 如果一個有native方法的類被繼承子類會繼承這個native方法,並且可以用java語言重寫

使用JNI(Java Native Interface) 與其他語言互動

JNIJava平臺的一部分,它允許Java程式碼和其他語言寫的程式碼進行互動。

使用步驟:

  • 編寫帶有native方法的java類,生成.java檔案
  • 使用javac命令編譯生成.class檔案
  • 使用javah -jni 類名 生成.h檔案
  • 使用C/C++(或者其他程式語言)實現native方法,建立.cpp(或其他)檔案
  • C/C++編寫的檔案建立動態連結庫(生成DLL檔案)
  • native方法中使用System.loadLibrary()方法載入動態庫,將DLL檔名作為引數傳入,這時候再執行.java程式即可實現對本地方法的呼叫

詳細步驟參考

native意義:

Java無法直接存取到作業系統底層(如系統硬體),但通過使用native關鍵字修飾方法可以借用其他的語言來擴充套件Java程式的功能,提高程式的效率

5.static

修飾變數,成為靜態變數或者類變數

  • 使用方法:存取修飾符+``static``+資料型別+變數名

注意事項:

  • 靜態變數會被類的所有物件範例共用,並且在類載入的時候就會初始化。
  • 靜態變數的存取方法(遵守相關存取許可權):類名.靜態變數名 或者 物件名.靜態變數名

修飾方法,成為靜態方法或者類方法

  • 使用方法:存取修飾符+``static``+返回資料型別+方法名+{}

注意事項:

  • 呼叫方法(遵守相關存取許可權):類名.靜態方法名 或者 物件名.靜態方法名
  • 靜態方法普通方法都是隨著類載入而載入,將結構資訊儲存在方法區
  • 靜態方法中不允許使用thissuper關鍵字
  • 靜態方法中只能存取靜態變數靜態方法
  • 普通方法可以存取靜態成員和普通成員
  • 修飾程式碼塊,成為靜態程式碼塊

靜態程式碼塊會在類載入時被載入,優先順序和靜態屬性一樣,有多個靜態程式碼塊和靜態屬性時,初始化順序按定義順序執行

好處:static關鍵字的使用,將類中的一些成員修飾成靜態的,這樣我們不需要建立該類的物件就可以呼叫該成員,大大提高了程式設計效率

6.transient

基本介紹:

transient用於修飾實現了Serilizable介面的類中的成員變數,在該類的範例物件進行序列化處理時transient修飾的成員變數不會進行序列化

使用例子:

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectOutputStream;
import java.io.Serializable;
public class outStream {
    public static void main(String[] args) throws IOException {
        String filePath = "d:Cat.txt";
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
        oos.writeObject(new Cat("小花貓", 3));
        oos.close();
    }
}
class Cat implements Serializable {
    private String name;
    private int age; //沒有用transient修飾
    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Car{" +

                "name='" + name + ''' +

                ", age=" + age +

                '}';
    }
}
public class inStream {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String filePath = "d:Cat.txt";
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
        System.out.println(ois.readObject());
        ois.close();
    }
}

可以在Cat.txt檔案內看到兩個成員變數都能被序列化,並且能被反序列化讀出資訊。

當小花貓覺得自己的年齡是隱私不想被讀出時,transient修飾成員變數age:

......
private String name;
private transient int age; //使用transient修飾
......

這時在Cat.txt檔案中可以看到只有name一個成員變數被序列化,反序列化後的成員變數age讀出的是int型別的預設值,說明對於transient修飾的成員變數,在類的範例物件序列化的過程中會被忽略

transient細節

  • transient修飾的成員變數可以理解為:不會參與進行物件的序列化和反序列化過程,生存週期僅存於呼叫者的記憶體不會寫進磁碟裡進行持久化
  • static修飾的成員變數(靜態變數)也是不可序列化的,不論被transient修飾與否

因為序列化是儲存的範例物件的狀態,而靜態變數儲存的是類的狀態

  • transient關鍵字只能修飾變數,不能修飾方法和類
  • transient關鍵字不能修飾區域性變數
  • transient關鍵字修飾的是自定義類的變數,則該類需要實現Serilizable介面

注意:

實現Serilizable介面的類的範例物件是自動進行序列化的,如果序列化物件的類實現的是Externalizable介面,則序列化不會自動進行,需要實現介面內的方法指定要序列化的變數,這時與有無Transient修飾無關

7.synchronized

基本介紹:

關鍵字synchronized可以保證在同一時刻只有一個執行緒可以執行被synchronized修飾的方法或程式碼塊

執行緒同步

程式中多個執行緒都要使用同一個方法,而這個方法用synchronized進行了修飾,在多個執行緒呼叫這個方法時必須遵循同步機制

執行緒同步機制

當一個執行緒使用synchronized修飾的方法時,其他執行緒想使用這個方法時就必須等待,直到這個執行緒使用完synchronized方法

synchronized使用方法:

  • 普通同步方法:public synchronized void m () {}
public class syn implements Runnable {
    static int i = 0;
    public static void main(String[] args) throws InterruptedException {
        syn test = new syn();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
    }
    public synchronized void increase() {//被synchronized修飾的同步方法
        System.out.println(Thread.currentThread().getName() + "呼叫:" + i++);

    }
    @Override
    public void run() {
        for (int j = 0; j < 100; j++) {
            increase();
        }
    }
}

兩個執行緒同時呼叫一個物件的一個同步方法,由於一個物件只有一把鎖,所以只有一個執行緒能夠獲得該物件的鎖,另一個執行緒無法獲得,就不能呼叫該物件的synchronized方法,需要等物件被釋放後才能呼叫

從執行結果中可以證明執行緒1搶到了鎖,執行緒0必須等待執行緒1執行完畢,否則不能存取該同步方法。

  • 靜態同步方法:public static synchronized void m () {}
public class syn implements Runnable {
    static int i = 0;
    public static void main(String[] args) throws InterruptedException {
        syn test = new syn();
        syn test1 = new syn();
        Thread t1 = new Thread(test);//傳入範例物件test
        Thread t2 = new Thread(test1);//傳入範例物件test1
        t1.start();
        t2.start();
    }
    public static synchronized void increase() {//同步靜態方法
        System.out.println(Thread.currentThread().getName() + "呼叫:" + i++);
    }
    @Override
    public void run() {
        for (int j = 0; j < 100; j++) {
            increase();
        }
    }
}

雖然兩個執行緒範例化了兩個不同的物件,但是synchronized修飾的是靜態方法,兩個執行緒仍然發生了互斥,因為靜態方法是依附與類的而不是物件,執行緒1先搶到了類的鎖,而執行緒0必須等待執行緒1執行完畢釋放才能呼叫同步方法

  • 同步程式碼塊:synchronized(object) {}
public class syn implements Runnable {
    static Object object = new Object();//共用物件
    public static void main(String[] args) throws InterruptedException {
        syn test = new syn();
        syn test1 = new syn();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test1);
        t1.start();
        t2.start();

    }
    @Override
    public void run() {
        synchronized (object) {//程式碼塊用靜態成員變數上鎖
            for (int j = 0; j < 100; j++) {
                System.out.println(Thread.currentThread().getName() + "呼叫第" + j + "次");
            }
        }
    }
}

同步程式碼塊用兩個範例變數共用的靜態成員object物件來上鎖,雖然是兩個執行緒範例化兩個不同的物件,但是對整個syn類來說只有一個共用的object物件,所以只有一把鎖,每當有執行緒來存取程式碼塊時需持有鎖,物件鎖被其他執行緒持有時需等待。執行緒1需要等執行緒0執行完畢才能存取同步程式碼塊

同步的侷限性:

由於同步的方法或程式碼塊只能同一時間讓一個執行緒存取,所以會導致程式的執行效率降低

儘可能synchronized修飾的範圍最小化,來減少互斥對程式執行帶來的影響

8.volatile

基本介紹:

volatile用於修飾變數,用volatile修飾的變數的值被某個執行緒修改時,會強制將修改的值立即寫入主記憶體中,主記憶體中的值更新會使得快取中的該變數的值失效,對比與非volatile變數,可能會被其他執行緒讀取到更新前的值。

使用方法:

//現在有執行緒1和執行緒2同時執行下列程式碼
int i = 0;
i = i + 1;

執行完畢後預想的結果是 i = 2;但是可能存在這樣一種情況:兩個執行緒先同時把i的值讀取到自己的工作記憶體中,然後再分別執行 i = i + 1 的操作,再將結果寫入主記憶體,這樣兩個執行緒寫入的都是 i = 1,最終 i 的結果是 1 ,而不是 2

但如果 i 是 volatile 修飾的變數就會不一樣了,在一個執行緒修改 i的值後,會立即強制在主記憶體中更新 i 的值,這樣會導致另一個執行緒的工作記憶體中 i 的快取值無效,所以另一個執行緒再次從主記憶體中讀取新的 i 的值,這樣保證了i的值是最新並正確的

並行程式設計的三大概念:

  • 原子性:執行一個操作時,要麼全部步驟執行完畢且不被中斷,要麼就不執行
x = 100;//是原子性操作
y = x;//不是原子性操作,可分解為:1.先讀取x的值    2.將x的值寫入主記憶體
x ++;//不是原子性操作,可分解為:1.讀取x的值    2.進行加一操作    3.寫入主記憶體
  • 可見性:多個執行緒對同一個變數進行操作時,一個執行緒修改了變數的值,其他執行緒能立即看到修改的值
  • 有序性:程式執行的順序按照程式碼的先後順序執行

volatile的意義

  • 保證了不同執行緒對變數進行修改時的可見性:因為對於volatile變數來說,被修改後新值對其他執行緒來說是立即可見的
  • 保證了有序性volatile禁止了指令重排,它能保證在對volatile修飾的變數進行操作時,之前的程式碼語句已經全部被執行,並且後面的語句都未執行,但是對其他語句的順序是不做保證的

注意: volatile不能保證原子性,因為不能保證對變數的操作是原子性操作

9.this

  • 在方法中修飾屬性,this理解為當前物件,用來區別成員方法和形參,通常省略
  • 修飾方法,this理解為當前物件,通常省略;不能在靜態方法中使用
  • 呼叫構造器,在構造器中使用this(形參列表)顯式呼叫指定的其他構造器
    • 必須在首行呼叫其他構造器
    • 一個構造器中不能呼叫多個其他構造器
    • 不能在構造器中呼叫遞迴呼叫,不能成環呼叫

10.super

super可以理解為:父類別的

  • 修飾屬性:去父類別中找對應屬性,用來區分子父類別重名的屬性
  • 修飾方法:呼叫重寫之前的方法
  • 呼叫構造器:使用super(形參列表)指定呼叫父類別構造器
    • super(形參列表)必須放在構造器的首行
    • super(形參列表)this(形參列表)只能二選一
    • 在構造器首行如果沒有顯式宣告super(形參列表)this(形參列表)則預設呼叫父類別的空參構造器super()(如果此時父類別中沒有空參構造器就會報錯)
  • 不能在靜態方法中使用

當一個方法和屬性被static屬性修飾時,這些方法和屬性是優先於物件載入進入記憶體的,是隨著類的載入而載入的;this是當前物件的參照,super是指父類別的參照,當靜態方法載入進記憶體進棧時,如果在靜態方法中有this和super關鍵字時,this和super也被載入到了記憶體,但是這個時候並沒有物件的參照,this和super沒有初始化,所有編譯會報錯。

10.1.子類物件範例化的過程

11.存取修飾符

public修飾類:

  • 一個類中最多隻能有一個public類,且檔名要和public類一致
  • 如果沒有public類,檔名可以任意

到此這篇關於Java幾個重要的關鍵字詳析的文章就介紹到這了,更多相關Java關鍵字內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com