iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
Software Development

深入淺出Java 30天系列 第 17

Day 17: 最小化類別、方法和欄位的存取權限

  • 分享至 

  • xImage
  •  

最小化存取權限的優點

所謂最小化存取權限,其實就是隱藏不必要給其他使用者知道資訊,這麼做的好處有:

  • 可以解耦和模組化系統:各類別或模組的規格訂完了之後,開發人員可以平行開發,互不干擾,因為除了最終完成的output是公開的,其他資訊都是獨立且被隱藏的。
  • 更好維護:不會因為修改影響其他模組或類別,因為洩漏的資訊不多,不用擔心改了其中一個欄位之後,才發現還有其他類別使用這個欄位,所以類別的欄位不應該被設為public,把欄位設為public,不只不好維護,還讓mutable的物件變得不thread-safe。
  • 更有效率的執行performance tuning:效能調校時不用擔心影響別的模組
  • 降低大型系統風險:如果模組的資訊有太多其他模組依賴,變動的時候容易造成其他模組受到影響,讓各模組獨立運作減少依賴,可以減少大型系統crash的風險。

Java有哪些存取權限

Java共有規範三種存取權限的modifier,分別是privateprotectedpublic,另外,如果類別、欄位或方法沒有modifier,則被視為package-private,這四種存取權限的定義如下:

  • private:只能被同一類別的其他成員存取。
  • package-private:只能被同一個package的類別存取,如果類別、欄位或方法沒有加modifier,預設會是package-private。如果該類別只有被一個類別使用,建議把該類別轉為nested class。
  • protected:只能被同一類別和子類別存取。
  • public:可以被所有類別存取。
    可以參考oracle官網提供的表格,記錄每個權限可以被存取的範圍

一些關於存取權限的注意事項

一般來說,如果被設為privatepackage-private,應該不會出現在exported API,但如果類別有實作Serializable,被設為privatepackage-private的欄位,有可能被洩漏出來。

子類別繼承父類別之後,子類別覆寫方法後的存取權限,不可低於父類別,舉例來說,父類別的方法如果是protected,子類別繼承後覆寫該方法,只能是protectedpublic,不能是privatepackage-private,不然會出現compile error。而interface的方法預設皆為public,實作的時候也不能改變。

而在測試時,常常會有"我想測這個方法,但是它是private,無法存取!!!"的問題,這時候可以將測試程式跟要測試的類別放在同一個package,並把方法的modifier,變成package-private,就可以在最小存取權限下進行測試。

原來static final不一定不能被修改!?

以Java的設計,有static final屬性的欄位,在類別實體化之後,應該不能被修改,但卻有一個例外,如果這個欄位存的型別是array,由於array是mutable的,即使是static final,一旦被設為public,還是可以被其它使用者修改。下面Draw這個範例,Draw被實體化了,但還是可以修改COLORS裡面的內容。

import java.util.Arrays;

public class Draw {
    // 設定一個 public static final 數組
    public static final String[] COLORS = {"Red", "Green", "Blue"};

    public static void main(String[] args) {
        Draw draw = new Draw();
        // 嘗試修改數組的內容
        draw.COLORS[0] = "Yellow";
        System.out.println(Arrays.toString(draw.COLORS));
    }
}

要避免這個情況,可以選擇改用list,並使用Collections.unmodifiableList產生immutable的list。

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Draw {
    // 設定一個 public static final 數組
    public static final List<String> COLORS = Collections.unmodifiableList(Arrays.asList("Red", "Green", "Blue"));

    public static void main(String[] args) {
        Draw draw = new Draw();
        // 嘗試修改數組的內容
        draw.COLORS.set(0, "Yellow");
        System.out.println(draw.COLORS);
    }
}

當嘗試要修改list內容的時候,runtime會丟出exception警告。

如果只能選擇使用public權限,要怎麼做比較好

如果真的想要把欄位設為public,那麼該欄位最好是immutable,並把欄位設為final,會讓改動之後的損害變得比較小。當然,如果是privatepackage-private的類別,把欄位設為public的影響比較沒那麼大,也是可被接受的。

除了把欄位設為final之外,也可以使用getter和setter,這樣調整欄位的時候只要確保getter和setter結果如預期即可,但如果是直接存取欄位,測試的範圍會變大。

Reference:
Controlling Access to Members of a Class


上一篇
Day 16: 考慮實作Comparable
下一篇
Day 18: 最小化可變性(上)
系列文
深入淺出Java 30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言