範圍
| 瀏覽 類和物件 主題: |
類、變數或方法的範圍是其可見性和可訪問性。可見性或可訪問性意味著您可以從給定位置使用該項。
方法引數在整個方法內可見,但在方法外部不可見。
程式碼清單 3.14:Scope.java
public class Scope {
public void method1(int i) {
i = i++;
method2();
int j = i * 2;
}
public void method2() {
int k = 20;
}
public static void main(String[] args) {
method1(10);
}
}
|
在 程式碼清單 3.14 中,i 在整個 method1 方法內可見,但在 method2 和 main 方法中不可見。
區域性變數在其聲明後可見,直到建立區域性變數的塊結束。
程式碼部分 3.50:區域性變數。
{
...
// myNumber is NOT visible
{
// myNumber is NOT visible
int myNumber;
// myNumber is visible
{
...
// myNumber is visible
}
// myNumber is visible
}
// myNumber is NOT visible
...
}
|
您肯定已經注意到,在本書中使用的類方法宣告的開頭有 public、protected 和 private 這些詞。這些關鍵字在 Java 語言語法中被稱為 訪問修飾符,它們定義了給定項的範圍。
- 如果類具有 public 可見性,則該類可以在程式中的任何地方被引用。
- 如果類具有 protected 可見性,則該類只能在定義類的包中被引用。
- 如果類具有 private 可見性(只有當該類在另一個類中定義為巢狀類時才會發生),則該類只能在外部類中被訪問。
- 如果變數在 public 類中定義,並且它具有 public 可見性,則該變數可以透過定義它的類在應用程式中的任何地方被引用。
- 如果變數具有 protected 可見性,則該變數只能在子類和同一個包中透過定義它的類被引用。
- 如果變數具有 package 可見性,則該變數只能在同一個包中透過定義它的類被引用。
- 如果變數具有 private 可見性,則該變數只能在定義它的類中被訪問。
- 如果方法在 public 類中定義,並且它具有 public 可見性,則該方法可以透過定義它的類在應用程式中的任何地方被呼叫。
- 如果方法具有 protected 可見性,則該方法只能在子類和同一個包中透過定義它的類被呼叫。
- 如果一個方法具有 **包** 可見性,則該方法只能透過定義它的類在同一個包中被呼叫。
- 如果一個方法具有 **私有** 可見性,則該方法只能在定義它的類中被呼叫。
對於介面
[edit | edit source]介面方法和介面始終是 public。你不需要指定訪問修飾符。它將預設設定為 public。為了清晰起見,建議使用 public 關鍵字。
同樣,在介面中定義的所有成員變數在繼承到類中後,預設將變為 static final。
總結
[edit | edit source]| 類 | 巢狀類 | 方法或成員變數 | 介面 | 介面方法簽名 | |
|---|---|---|---|---|---|
public
|
從任何地方可見 | 與它的類相同 | 與它的類相同 | 從任何地方可見 | 從任何地方可見 |
protected
|
N/A | 它的類和它的子類 | 它的類和它的子類,以及它的包 | N/A | N/A |
| package | 僅從它的包可見 | 僅從它的包可見 | 僅從它的包可見 | N/A | N/A |
private
|
N/A | 僅從它的類可見 | 僅從它的類可見 | N/A | N/A |
粗體部分是預設情況。
實用工具
[edit | edit source]可見性的一個一般準則是隻讓成員儘可能可見。如果一個成員只需要是私有的,就不要把它設為公有的。
這樣做,你可以重寫一個類並更改所有私有成員而不會出現編譯錯誤,即使你不知道所有使用你的類的類,只要你不更改公共成員的簽名。
欄位封裝
[edit | edit source]通常,最好將資料設為私有或受保護。對資料的訪問由 *setter* 和 *getter* 方法控制。這樣可以讓程式設計師控制對資料的訪問,允許他們檢查和處理無效資料。
程式碼部分 3.51:封裝。
private String name;
/**
* This is a getter method because it accesses data from the object.
*/
public String getName() {
return name;
}
/**
* This is a setter method because it changes data in the object.
*/
public boolean setName(String newName) {
if (newName == null) {
return false;
} else {
name = newName;
return true;
}
}
|
在 程式碼部分 3.51 中,setName() 方法只有在新名稱不為空的情況下才會更改 name 的值。因為 setName() 是有條件地更改 name 的,所以最好返回一個布林值,讓程式知道更改是否成功。
**問題 3.15**: 考慮以下類。
問題 3.15:Question15.java
public class Question15 {
public static final int QKQKQKQK_MULTIPLIER = 2;
public int ijijijijijijijijijAwfulName = 20;
private int unununununununununCrummyName = 10;
private void mememememememeUglyName(int i) {
i = i++;
tltltltltltltltltlBadName();
int j = i * QKQKQKQK_MULTIPLIER;
}
public void tltltltltltltltltlBadName() {
int k = ijijijijijijijijijAwfulName;
}
public static void main(String[] args) {
mememememememeUglyName(unununununununununCrummyName);
}
}
|
列出此類中可以重新命名而無需更改或甚至不知道客戶端類的欄位和方法。
unununununununununCrummyNamemememememememeUglyName()
每個公有的欄位或方法都可以被客戶端類直接呼叫,因此如果該欄位或方法具有新名稱,則該類將返回編譯錯誤。