你好!在今天的課程中,我們將熟悉訪問修飾符的概念,並考慮如何使用它們的示例。當然,說“熟悉”並不完全正確:您已經從之前的課程中熟悉其中的大部分內容。為了以防萬一,讓我們回顧一下最重要的一點。修飾符訪問通常是關鍵字,用於調節對代碼不同部分的訪問。為什麼是“最經常”?因為其中之一是默認設置的,沒有使用關鍵字 :) Java 有四種訪問修飾符。我們按照從最嚴格到最“寬鬆”的順序列出它們:
private是最嚴格的訪問修飾符。它將數據和方法的可見性限制在單個類中。您從關於 getter 和 setter 的課程中知道了這個修飾符。還記得這個例子嗎?
訪問修飾符標記的字段和方法將可見:
現在您已經學習了有關接口的課程,其目的對您來說是顯而易見的 :) 畢竟,創建public修飾符是為了向用戶提供一些東西。例如,您的程序的界面。假設您編寫了一個可以將俄語文本翻譯成英語的翻譯程序。您創建了一個實現所有必要邏輯的translate(String textInRussian)方法。您用public這個詞標記了這個方法,現在它是接口的一部分:
- 私人的;
- 默認(包可見);
- 受保護;
- 民眾。
私有修飾符

public class Cat {
public String name;
public int age;
public int weight;
public Cat(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public Cat() {
}
public void sayMeow() {
System.out.println("Meow!");
}
}
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
cat.name = "";
cat.age = -1000;
cat.weight = 0;
}
}
我們在上一課中考慮過它。我們在這裡犯了一個嚴重的錯誤:我們公開了我們的數據,這使得其他程序員可以直接訪問這些字段並更改它們的值。更重要的是......這些值是在沒有任何檢查的情況下分配的。這意味著我們的程序可以創建一隻名為“”的貓,年齡為-1000 歲,體重為 0。為了解決這個問題,我們使用了 getter 和 setter,還使用了 private 修飾符來限制對數據的訪問。
public class Cat {
private String name;
private int age;
private int weight;
public Cat(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public Cat() {
}
public void sayMeow() {
System.out.println("Meow!");
}
public String getName() {
return name;
}
public void setName(String name) {
// input parameter check
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
// input parameter check
this.age = age;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
// input parameter check
this.weight = weight;
}
}
基本上,限制對字段的訪問和實現 getter 和 setter 是最常見的私有化示例會用到實際工作中。也就是說,這個修飾符的主要目的是在程序中實現封裝。順便說一句,這不僅適用於字段。想像一下,在您的程序中有一個方法可以實現一些非常複雜的功能。我們可以舉個例子嗎?假設您的 readDataFromCollider() 方法接受數據地址作為輸入,以字節格式從大型強子對撞機讀取數據,將此數據轉換為文本,將其寫入文件並打印。連方法的描述看起來都嚇人,更不用說代碼了:) 為了使代碼更具可讀性,最好不要將所有方法的複雜邏輯都寫在一個地方。相反,我們應該將功能分解為單獨的方法。例如,readByteData()方法負責讀取數據,convertBytesToSymbols()方法將從collider讀取的數據轉換為文本,saveToFile()方法將接收到的文本保存到文件中,printColliderData ()方法打印我們的數據文件。最後,我們的readDataFromCollider()方法會簡單得多:
public class ColliderUtil {
public void readDataFromCollider(Path pathToData) {
byte[] colliderData = readByteData(pathToData);
String[] textData = convertBytesToSymbols(colliderData);
File fileWithData = saveToFile(textData);
printColliderData(fileWithData);
}
public byte[] readByteData(Path pathToData) {
// Reads data in bytes
}
public String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
// Converts bytes to characters
}
public File saveToFile(String[] colliderData) {
// Saves read data to a file
}
public void printColliderData(File fileWithColliderData) {
// Prints data from the file
}
}
但是,正如您從有關接口的課程中所記得的那樣,用戶只能訪問外部接口。而我們的4個方法不在其中。它們是輔助方法:我們創建它們是為了提高代碼的可讀性,而不是將四個不同的任務塞進一個方法中。您不需要授予用戶訪問這些方法的權限。如果用戶在使用碰撞器時可以訪問convertBytesToSymbols()方法,他們很可能只是對該方法感到困惑,並想知道它的用途。轉換了哪些字節?哪兒來的呢?為什麼要將它們轉換為文本?在此方法中執行的邏輯不是向用戶公開的界面的一部分。只有readDataFromCollider()方法是接口的一部分。那麼我們如何處理這四種“內部”方法呢?正確的!使用private修飾符來限制對它們的訪問。這樣做允許他們在類中和平地執行他們的工作,而不會混淆用戶,用戶不需要知道每個單獨方法的邏輯。
public class ColliderUtil {
public void readDataFromCollider(Path pathToData) {
byte[] colliderData = readByteData(pathToData);
String[] textData = convertBytesToSymbols(colliderData);
File fileWithData = saveToFile(textData);
printColliderData(fileWithData);
}
private byte[] readByteData(Path pathToData) {
// Reads data in bytes
}
private String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
// Converts bytes to characters
}
private File saveToFile(String[] colliderData) {
// Saves read data to a file
}
private void printColliderData(File fileWithColliderData) {
// Prints data from the file
}
}
受保護修飾符
下一個最嚴格的修飾符是protected。 受保護
- 在與我們相同的包中包含的所有類中;
- 在繼承我們類的所有類中。
public abstract class AbstractSecretAgent {
public static int agentCount = 0;
}
但我們的特工是保密的!這意味著他們而不是其他人應該知道其中有多少存在。我們可以輕鬆地將protected修飾符添加到agent_counter字段。然後其他秘密特工類和位於我們的top_secret包中的其他類的實例可以獲取它的值。
public abstract class AbstractSecretAgent {
protected static int agent_counter = 0;
}
這就是需要protected修飾符 的專門任務:)
包可見修飾符
列表中的下一個是默認修飾符,也稱為包可見修飾符。它不是由關鍵字指示的,因為 Java 默認將它應用於所有字段和方法。如果您在代碼中編寫以下內容:
int x = 10
x變量將具有此包可見訪問權限。很容易記住它的作用。基本上,default = protected inheritance :) 和protected修飾符一樣,它的應用是有限的。大多數情況下,默認訪問用於包含一些實用程序類的包中,這些實用程序類未實現包中所有其他類的功能。讓我們舉個例子。想像一下,我們有一個“服務”包。它包含各種與數據庫一起工作的類。比如有一個從數據庫中讀取用戶數據的UserService類,一個CarService從同一數據庫和其他類讀取汽車數據的類,每個類都使用特定類型的對象並從數據庫中讀取相應的數據。
package services;
public class UserService {
}
package services;
public class CarService {
}
但是數據庫中的數據很容易是一種格式,而我們需要另一種格式。假設用戶的生日在數據庫中存儲為 <TIMESTAMP WITH TIME ZONE>...
2014-04-04 20:32:59.390583+02
...相反,我們需要最簡單的對象 — java.util.Date。為了解決這個問題,在services包裡面,我們可以創建一個特殊的Mapper類。它將負責將數據從數據庫轉換為我們熟悉的 Java 對象。一個簡單的幫助類。我們通常將所有類都聲明為public class ClassName,但這不是必需的。我們可以將我們的助手類簡單地聲明為class Mapper。在這種情況下,它仍然可以正常工作,但服務包之外的任何人都看不到它!
package services;
class Mapper {
}
package services;
public class CarService {
Mapper mapper;
}
這是基本的推理:為什麼包外的任何人都需要看到一個僅適用於該包中的類的助手類?
公共修飾符
最後但同樣重要的是,公共修飾符!您在學習 CodeGym 的第一天第一次運行public static void main(String[] args)時遇到了這個修飾符。
public class Translator {
public String translate(String textInRussian) {
// Translates text from Russian to English
}
}
您可以將此方法綁定到屏幕上的“翻譯”按鈕,您就完成了!任何人都可以使用它。標有public修飾符的代碼部分供最終用戶使用。舉一個真實的例子,private是針對電視內部發生的所有進程,而public是針對遙控器上用於管理電視的按鈕。更重要的是,用戶不需要知道電視是如何製造的或它是如何工作的。遙控器是一組公共方法:on()、off()、nextChannel()、previousChannel()、increaseVolume()、decreaseVolume()等。 為了鞏固您所學的知識,我們建議您觀看我們的 Java 課程中的視頻課程
GO TO FULL VERSION