修飾子(Modifiers)

Posted by Bruce Tsai

native

native 是方法修飾子。 native 方法是由另外一種語言(如 c/c++、FORTRAN)實作的函式庫。因為在外部實現了方法的實作,所以在 Java 的原始碼中,不需要再實作其內容,僅需將方法標示為 native ,類似於介面的宣告方式。native 可以和其他一些修飾子並用,但無法在 abstract 及 interface 中使用。

public interface TestInterface {

    void doMethod();

}

public class Test implements TestInterface {

    public native void doMethod();

    private native int doMethodB();

    public native synchronized String doMethodC();

    static native void doMethodD();

}

strictfp

用於類別和方法,意思是精確浮點(fp:strict)。當 Java 虛擬機進行浮點運算時,如果沒有指定 strictfp 關鍵字時,Java 的編譯器以及執行環境在對浮點運算的運算式是採取一種近似於我行我素的行為來完成這些操作,以致於得到的結果往往無法令你滿意。而一旦使用了 strictfp 來宣告一個類別、介面或者方法時,那麼所宣告的範圍內 Java 的編譯器以及執行環境會完全依照浮點規範 IEEE-754 來執行。因此如果你想讓你的浮點運算更加精確,而且不會因為不同的平台所執行的結果不一致的話,那就請用關鍵字 strictfp。當一個類別或介面用 strictfp 宣告時,內部所有的 float 和 double 運算式都會被視為宣告了 strictfp 修飾子。

注意:可以將一個類別、介面以及方法宣告為 strictfp,但是不允許對介面中的方法以及建構子宣告 strictfp 關鍵字。

class FPClass implements FPTest {

    public void methodA() {

    }

    public void methodB() {

    }


    public strictfp void methodC() {

    }

}

class FPClassB {

    strictfp void methodA() {

    }

}

transient

成員(Field)修飾子。標記為 transient 的成員,在物件序列化時,這些成員的值將不會被序列化。若要將物件序列化保存或進行傳遞時,不希望其中一些成員的資訊露出,為了保證安全性,可以把這些成員宣告為 transient 修飾子。

public class Manager {

    private String account;

    private transient String password;

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

volatile

volatile 修飾成員。在每次被執行緒存取時,都強迫從記憶體中重讀該成員變數的值。而且當成員變數發生變化時,強迫執行緒將變化的值回寫到記憶體。這樣在任何時刻,兩個不同的執行緒會看到某個成員變數的值為相同。

實驗範例

條件:一個執行緒不斷的呼叫方法 one(),另一個執行緒不斷的呼叫方法 two()

class Test {

    static int i = 0, j = 0;

    static void one() {
        i++;
        j++;
    }

    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }

}

結果偶爾會出現 j 大於 i 的情況,因為方法沒有同步,所以會出現 i 和 j 可能不是一次更新。一種途徑就是把 i 和 j 聲明為 volatile。

class Test {

    volatile static int i = 0, j = 0;

    static void one() {
        i++;
        j++;
    }

    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }

}

synchronized

synchronized 有兩種撰寫方法:

  1. synchronized method 當同時有多個執行緒存取方法時,先到者優先使用,後到者必須持續等待前一個執行緒執行完離開方法後,釋放其 lock 才可進入使用 synchronized method 其 lock 是該類別的 lock,因此如果這個類別擁有兩個以上的同步化方法,而又有多個執行緒存取該類別不同個的同步化方法,也是只會只有一個執行緒可以正常進入執行,其他執行緒仍然必須等待,因為 lock 是 class lock,鎖住的是一整個類別。

  2. synchronizated block 為了減少 synchronized 過於影響執行效率,所以期望把受影響的範圍縮小,因此使用其他物件來當 lock,但仍然可用 class lock,將 lock 指定為 this 即可。

實驗範例

同上例,另一種防止這種情況發生的辦法就是宣告兩個方法為 synchronized。這樣可以防止兩個方法同時被執行,還可以保證 j 和 i 被同時更新,這樣一來 i 和 j 的值一直是一樣的。

class Test {

    static int i = 0, j = 0;

    static synchronized void one() {
        i++;
        j++;
    }

    static synchronized void two() {
        System.out.println("i=" + i + " j=" + j);
    }

}

results matching ""

    No results matching ""