在 Java 語言中提供了多個作用域修飾符,其中常用的有 public、private、protected、final、abstract、static、transient 和 volatile,這些修飾符有類修飾符、變量修飾符和方法修飾符。本文將詳細介紹訪問控制修飾符。
在實際生活中,如果要獲取某件物品,與其直接穿過堡壘的牆壁,從而導致牆壁毀滅和破壞,不如通過門口的警衛請求進入堡壘的許可。一般而言,這對對象同樣適用:沒有對象的許可(即對象的屬性是私有的),不能直接訪問該對象的私有屬性。
信息隱藏是 OOP 最重要的功能之一,也是使用訪問修飾符的原因。在編寫程序時,有些核心數據往往不希望被用戶調用,需要控制這些數據的訪問。
對類成員訪問的限制是面向對象程序設計的一個基礎,這有利於防止對象的誤用。只允許通過一系列定義完善的方法來訪問私有數據,就可以(通過執行範圍檢查)防止數據賦予不正當的值。例如,類以外的代碼不可能直接向一個私有成員賦值。同時,還可以精確地控制如何以及何時使用對象中的數據。
當正確實現對類成員的方法控制後,類就可以創建一個可用的“黑箱”,其內部動作不會被打開而任意篡改。
通過使用訪問控制修飾符來限制對對象私有屬性的訪問,可以獲得 3 個重要的好處。
- 防止對封裝數據的未授權訪問。
- 有助於保證數據完整性。
- 當類的私有實現細節必須改變時,可以限制發生在整個應用程序中的“連鎖反應”。
訪問控制符是一組限定類、屬性或方法是否可以被程序裏的其他部分訪問和調用的修飾符。類的訪問控制符只能是空或者 public,方法和屬性的訪問控制符有 4 個,分別是 public、 private、protected 和 friendly,其中 friendly 是一種沒有定義專門的訪問控制符的默認情況。訪問控制修飾符的權限如表 1 所示。
訪問範圍 | private | friendly(默認) | protected | public |
---|---|---|---|---|
同一個類 | 可訪問 | 可訪問 | 可訪問 | 可訪問 |
同一包中的其他類 | 不可訪問 | 可訪問 | 可訪問 | 可訪問 |
不同包中的子類 | 不可訪問 | 不可訪問 | 可訪問 | 可訪問 |
不同包中的非子類 | 不可訪問 | 不可訪問 | 不可訪問 | 可訪問 |
訪問控制在面向對象技術中處於很重要的地位,合理地使用訪問控制符,可以通過降低類和類之間的耦合性(關聯性)來降低整個項目的複雜度,也便於整個項目的開發和維護。在 Java 語言中,訪問控制修飾符有 4 種。
1. private
用 private 修飾的類成員,只能被該類自身的方法訪問和修改,而不能被任何其他類(包括該類的子類)訪問和引用。因此,private 修飾符具有最高的保護級別。例如,設 PhoneCard 是電話卡類,電話卡都有密碼,因此該類有一個密碼域,可以把該類的密碼域聲明爲私有成員。
2. friendly(默認)
如果一個類沒有訪問控制符,說明它具有默認的訪問控制特性。這種默認的訪問控制權規定,該類只能被同一個包中的類訪問和引用,而不能被其他包中的類使用,即使其他包中有該類的子類。這種訪問特性又稱爲包訪問性(package private)。
同樣,類內的成員如果沒有訪問控制符,也說明它們具有包訪問性,或稱爲友元(friend)。定義在同一個文件夾中的所有類屬於一個包,所以前面的程序要把用戶自定義的類放在同一個文件夾中(Java 項目默認的包),以便不加修飾符也能運行。
3. protected
用保護訪問控制符 protected 修飾的類成員可以被三種類所訪問:該類自身、與它在同一個包中的其他類以及在其他包中的該類的子類。使用 protected 修飾符的主要作用,是允許其他包中它的子類來訪問父類的特定屬性和方法,否則可以使用默認訪問控制符。
4. public
當一個類被聲明爲 public 時,它就具有了被其他包中的類訪問的可能性,只要包中的其他類在程序中使用 import 語句引入 public 類,就可以訪問和引用這個類。
類中被設定爲 public 的方法是這個類對外的接口部分,避免了程序的其他部分直接去操作類內的數據,實際就是數據封裝思想的體現。每個 Java 程序的主類都必須是 public 類,也是基於相同的原因。
例 1
下面來創建一個示例,演示 Java 中訪問控制修飾符的使用。
(1) 新建 Student.java 文件,在該文件中定義不同修飾符的屬性和方法,代碼如下:
- class Student {
- // 姓名,其訪問權限爲默認(friendly)
- String name;
- // 定義私有變量,身份證號碼
- private String idNumber;
- // 定義受保護變量,學號
- protected String no;
- // 定義共有變量,郵箱
- public String email;
- // 定義共有方法,顯示學生信息
- public String info() {
- return"姓名:"+name+",身份證號碼:"+idNumber+",學號:"+no+",郵箱:"+email;
- }
- }
(2) 新建 StudentTest.java 文件,在該文件中定義 main() 方法,訪問 Student 類中的屬性並賦值,打印出用戶的信息。代碼如下:
- public class StudentTest {
- public static void main(String[] args) {
- // 創建Student類對象
- Student stu = new Student();
- // 向Student類對象中的屬性賦值
- stu.name = "zhht";
- // stu.idNumber="043765290763137806";
- // 這是不允許的。提示stu.idNumber是不可見的,必須註釋掉纔可運行
- stu.no = "20lil01637";
- stu.email = "[email protected]";
- System.out.println(stu.info());
- }
- }
在 StudentTest 類中,“stu.idNumber="043765290763137806";”代碼行將提示 “The field User.password is not visible”錯誤信息。將該代碼行註釋掉再運行 StudentTest.java 文件,輸出的內容如下:
姓名:zhht,身份證號碼:null,學號:20lil01637,郵箱:[email protected]
在源文件中創建了兩個類,分別爲主類 StudentTest 和輔助類 Student,二者在同一個包中。
在輔助類 Student 中,創建了 4 個屬性,其訪問控制分別爲默認的、私有的、受保護的和共有的,除了私有控制符修飾的變量之外,其他的都可以被主類訪問,同時創建了一個共有的方法——info(),用於打印用戶信息。
在主類 StudentTest 中,創建類 Student 的實例化對象 stu,通過對象 stu 來訪問該對象中的屬性並賦值,因爲 idNumber 屬性的修飾符爲 private(私有的),因此,在 StudentTest 類中的 main() 方法中無法訪問該屬性。
從上面的例子中可以看出,範圍控制修飾符成功地限制了訪問者訪問不同修飾符的屬性(成員變量),從而實現了數據的隱藏。