在Java中,我們經常看到
public
、protected
、private
這些修飾符。在Java中,這些修飾符可以用來限定訪問作用域。
public
定義爲public
的class
、interface
可以被其他任何類訪問:
package abc;
public class Hello {
public void hi() {
}
}
上面的Hello
是public
,因此,可以被其他包的類訪問:
package xyz;
class Main {
void foo() {
// Main可以訪問Hello
Hello h = new Hello();
}
}
定義爲public
的field
、method
可以被其他類訪問,前提是首先有訪問class
的權限:
package abc;
public class Hello {
public void hi() {
}
}
上面的hi()
方法是public
,可以被其他類調用,前提是首先要能訪問Hello
類:
package xyz;
class Main {
void foo() {
Hello h = new Hello();
h.hi();
}
}
private
定義爲private
的field
、method
無法被其他類訪問:
package abc;
public class Hello {
// 不能被其他類調用:
private void hi() {
}
public void hello() {
this.hi();
}
}
實際上,確切地說,private
訪問權限被限定在class
的內部,而且與方法聲明順序無關。推薦把private
方法放到後面,因爲public
方法定義了類對外提供的功能,閱讀代碼的時候,應該先關注public
方法:
package abc;
public class Hello {
public void hello() {
this.hi();
}
private void hi() {
}
}
由於Java支持嵌套類,如果一個類內部還定義了嵌套類,那麼,嵌套類擁有訪問private
的權限:
public class Main {
public static void main(String[] args) {
Inner i = new Inner();
i.hi();
}
// private方法:
private static void hello() {
System.out.println("private hello!");
}
// 靜態內部類:
static class Inner {
public void hi() {
Main.hello();
}
}
}
輸出:
private hello!
定義在一個class
內部的class
稱爲嵌套類(nested class
),Java支持好幾種嵌套類。
protected
protected
作用於繼承關係。定義爲protected
的字段和方法可以被子類訪問,以及子類的子類:
package abc;
public class Hello {
// protected方法:
protected void hi() {
}
}
上面的protected
方法可以被繼承的類訪問:
package xyz;
class Main extends Hello {
void foo() {
Hello h = new Hello();
// 可以訪問protected方法:
h.hi();
}
}
package
最後,包作用域是指一個類允許訪問同一個package
的沒有public
、private
修飾的class
,以及沒有public
、protected
、private
修飾的字段和方法。
package abc;
// package權限的類:
class Hello {
// package權限的方法:
void hi() {
}
}
只要在同一個包,就可以訪問package
權限的class
、field
和method
:
package abc;
class Main {
void foo() {
// 可以訪問package權限的類:
Hello h = new Hello();
// 可以調用package權限的方法:
h.hi();
}
}
注意,包名必須完全一致,包沒有父子關係,com.apache
和com.apache.abc
是不同的包。
局部變量
在方法內部定義的變量稱爲局部變量,局部變量作用域從變量聲明處開始到對應的塊結束。方法參數也是局部變量。
package abc;
public class Hello {
void hi(String name) { // ①
String s = name.toLowerCase(); // ②
int len = s.length(); // ③
if (len < 10) { // ④
int p = 10 - len; // ⑤
for (int i=0; i<10; i++) { // ⑥
System.out.println(); // ⑦
} // ⑧
} // ⑨
} // ⑩
}
我們觀察上面的hi()
方法代碼:
-
方法參數name是局部變量,它的作用域是整個方法,即①~⑩;
-
變量s的作用域是定義處到方法結束,即②~⑩;
-
變量len的作用域是定義處到方法結束,即③~⑩;
-
變量p的作用域是定義處到if塊結束,即⑤~⑨;
-
變量i的作用域是for循環,即⑥~⑧。
使用局部變量時,應該儘可能把局部變量的作用域縮小,儘可能延後聲明局部變量。
final
Java還提供了一個final
修飾符。final
與訪問權限不衝突,它有很多作用。
用final
修飾class
可以阻止被繼承:
package abc;
// 無法被繼承:
public final class Hello {
private int n = 0;
protected void hi(int t) {
long i = t;
}
}
用final
修飾method
可以阻止被子類覆寫:
package abc;
public class Hello {
// 無法被覆寫:
protected final void hi() {
}
}
用final
修飾field
可以阻止被重新賦值:
package abc;
public class Hello {
private final int n = 0;
protected void hi() {
this.n = 1; // error!
}
}
用final
修飾局部變量可以阻止被重新賦值:
package abc;
public class Hello {
protected void hi(final int t) {
t = 1; // error!
}
}
最佳實踐
如果不確定是否需要public
,就不聲明爲public
,即儘可能少地暴露對外的字段和方法。
把方法定義爲package
權限有助於測試,因爲測試類和被測試類只要位於同一個package
,測試代碼就可以訪問被測試類的package
權限方法。
一個.java
文件只能包含一個public
類,但可以包含多個非public
類。如果有public
類,文件名必須和public
類的名字相同。
小結
Java內建的訪問權限包括public
、protected
、private
和package
權限;
Java在方法內部定義的變量是局部變量,局部變量的作用域從變量聲明開始,到一個塊結束;
final
修飾符不是訪問權限,它可以修飾class
、field
和method
;
一個.java
文件只能包含一個public
類,但可以包含多個非public
類。