你好!在今天的講座中,我們將熟悉「訪問修飾符」的概念並查看使用它們的範例。 儘管「讓我們熟悉一下」這個詞並不完全正確:您已經從之前的講座中熟悉了其中的大多數。以防萬一,讓我們回顧一下主要的事情。 存取修飾符通常是調節對程式碼不同部分的存取等級的關鍵字。為什麼「最經常」?因為其中一個是預設設定的,而且不是由關鍵字指示的:) Java中總共有四種存取修飾符。我們按照從最嚴格到最“軟”的順序列出它們:
- 私人的;
- 受保護;
- 預設(包可見);
- 民眾
修飾符私有
Private
——最嚴格的存取修飾符。它限制了單一類別中資料和方法的可見性。您從關於 getter 和 setter 的講座中了解了這個修飾符。你還記得這個例子嗎?
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) {
// checking the input parameter
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
// checking the input parameter
this.age = age;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
// checking the input parameter
this.weight = weight;
}
}
實際上,限制對欄位的存取和實作 getter-setter 是實際工作中最常見的使用範例private
。 也就是說,在程式中實作封裝是該修飾符的主要目的。 順便說一句,這不僅適用於領域。想像一下,在您的程式中,有一個方法實作了一些非常複雜的功能。以此為例...假設您的方法readDataFromCollider()
採用一個帶有數據的地址作為輸入,以字節格式從大型強子對撞機讀取數據,將該數據轉換為文本,將其寫入文件並打印。連方法的描述都顯得毛骨悚然,更不用說程式碼了:)為了增加程式碼的可讀性,最好不要把方法的複雜邏輯寫在一處,而是相反,破壞功能分成單獨的方法。例如,該方法readByteData()
負責讀取數據,convertBytesToSymbols()
將從碰撞器讀取的數據轉換為文本,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) {
// convert bytes to characters
}
public File saveToFile(String[] colliderData) {
// save the read data to a file
}
public void printColliderData(File fileWithColliderData) {
// print data from 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) {
// convert bytes to characters
}
private File saveToFile(String[] colliderData) {
// save the read data to a file
}
private void printColliderData(File fileWithColliderData) {
// print data from file
}
}
修飾符保護
下一個最嚴格的存取修飾符是protected
. 使用存取修飾符指定的欄位和方法protected
將可見:
- 在與我們的包相同的所有類別中;
- 在我們班的所有後繼班級中。
protected
應用案例比 少得多private
,而且很具體。想像一下,我們有一個AbstractSecretAgent
表示某個情報機構的秘密特工的抽象類,以及top_secret
包含該類及其後代的包。具體類別 - FBISecretAgent
、MI6SecretAgent
等MossadSecretAgent
-都是從它繼承的。在抽象類別中,我們想要實作一個代理計數器。當程式中某處建立新的代理物件時,它會增加。
package top_secret;
public abstract class AbstractSecretAgent {
public static int agentCount = 0;
}
但我們的代理人是秘密的!這意味著只有他們自己才能知道他們的號碼。protected
我們可以輕鬆地在欄位中新增修飾符agentCount
,然後其他秘密代理類別的物件或位於我們的「秘密」包中的那些類別都可以取得其值top_secret
。
public abstract class AbstractSecretAgent {
protected static int agentCount = 0;
}
對於此類特定任務,需要修飾符protected
:)
包可見修飾符
我們清單中的下一個是修飾符default
,或者也稱為package visible
。它不是由關鍵字指示的,因為它是 Java 中所有欄位和方法的預設。如果你在程式碼中寫入 -
int x = 10;
...變數x
將具有相同的package visible
存取權限。如果方法(或變數)未使用任何修飾符進行標記,則視為使用「預設修飾符」進行標記。具有此類修飾符(即根本沒有任何修飾符)的變數或方法對於聲明它們的包中的所有類別都是可見的。並且只對他們而言。它的用途是有限的,就像修飾符一樣protected
。最常見的是,default
-access 用於一個包中,其中有一些實用程式類別沒有實現該套件中所有其他類別的功能。讓我們舉個例子。想像一下我們有一個「服務」包。其中包含與資料庫一起使用的各種類別。例如,有一個類別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
. 在這種情況下,它仍然可以完成其工作,但對於包之外的任何人都看不到services
!
package services;
class Mapper {
}
package services;
public class CarService {
Mapper mapper;
}
事實上,這是正確的邏輯:為什麼包外的人會看到一個只能與同一包的類別一起使用的輔助類別?
公共修飾符
最後,但並非最不重要的 - 修飾符public
!您在 JavaRush 學習的第一天就遇到了他,當時他正在啟動public static void main(String[] args)
. 現在你已經學習了有關介面的講座,它的目的對你來說是顯而易見的:)畢竟,public
它是為了給用戶一些東西而創建的。例如,您的程式的介面。假設您編寫了一個翻譯程序,它可以將俄文文字翻譯成英文。您已經建立了一個方法,translate(String textInRussian)
在該方法中實作了必要的邏輯。您用單字 標記了該方法public
,現在它將成為介面的一部分:
public class Translator {
public String translate(String textInRussian) {
// translates text from Russian to English
}
}
您可以將此方法的呼叫與程式畫面上的“翻譯”按鈕關聯起來 - 就是這樣!任何人都可以使用它。標有修飾符的部分程式碼public
是供最終用戶使用的。舉個生活中的例子,private
這些都是電視工作時內部發生的所有過程,public
這些都是電視遙控器上使用者可以控制電視的按鈕。同時,他也不需要知道電視的工作原理和運作原理。遙控器是一組public
方法:on()
、off()
、nextChannel()
、previousChannel()
、increaseVolume()
等decreaseVolume()
。
GO TO FULL VERSION