JAVA的通路控制2-public,protected,private和package-private
在前文JAVA的通路控制1-通路控制的必要性,包中介紹了通路控制的由來以及包的概念,本文将繼續介紹通路控制的關鍵字public,protected,private以及沒有關鍵字時預設的package-private。
這些關鍵字可以用于修飾字段,方法和内部類,另外,隻有public和預設的package-private可以用于外部類定義。
package-private預設權限
當字段等沒有任何修飾符時,就是預設權限,也就是包通路權限。包通路權限可以讓目前包的所有類進行調用,其他包的類則無法調用。
比如,類Persion在包org.xxx.model下,代碼如下:
package org.xxx;
public class Person {
String name;
String getName() {
return name;
}
}
那麼,同樣在包org.xxx.model下的其他類就可以通路到name字段和getName()方法,而其他包,比如org.xxx.util包下的類,就無法通路。
預設權限的一個用途是單元測試,被測試類中一些待測試字段和方法設定為預設權限,測試類可以友善地設定和調用。
大部分的方法都可以設定為包通路權限。
public
public關鍵字表示所有人都可以通路,通常是用于對外開放的方法上,如下所示:
package org.xxx.package1;
public class Formatter{
public String describe() {
return "formatter";
}
}
Formatter的包是org.xxx,提供了一個describe()的方法,該方法可以被任何類調用。可以像下面這樣來使用:
package org.xxx.package2;
import org.xxx.package1.Formatter;
public class User{
public String describeFormatter() {
Formatter formatter = new Formatter();
return formatter.describe();
}
}
使用Formatter的類位于另一個包下面,是可以正常使用的。
一般而言,不建議public修飾字段,如果開放某個字段,可以提供對應的getter和setter方法,比如:
public class Person {
// private修飾符 後面會提到
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
這個也叫java bean,是一種非常常見的使用方法。
public修飾字段一般是用于常量的聲明,比如一周有七天,很多地方需要使用這個資訊,就可以聲明一個常量public static final int DAYS_OF_WEEK = 7;,後面需要用這個數字進行計算的都使用DAYS_OF_WEEK常量來計算,可以使代碼比較清晰明了。
private
private關鍵字意味着這個方法/字段無法被其他類以正常方法(非正常方法指反射)通路,包括同一個包裡面的其他類,也無法通路。下面是一個樣例:
public class Constants {
public static final int DAYS_OF_WEEK = 7;
private Constants() {
}
}
這個樣例中,private被用到了構造器上,說明這個類無法被其他類通過new Constants()的方法執行個體化,原因是這個類是用于定義常量的類,它本身不需要被執行個體化。上文提到的常量一般可以通過這種方式定義。
如果某個常量隻在一個類裡面使用,也可以直接定義在類内部,比如:
public class WeekUtil {
private static final int DAYS_OF_WEEK = 7;
public static int daysOfWeeks(int weekNum) {
return DAYS_OF_WEEK * weekNum;
}
}
daysOfWeeks(int weekNum)方法可以計算指定周數有多少天,這裡就使用private來定義了DAYS_OF_WEEK常量。
protected
protected修飾的内容可以被子類通路,無論子類在哪個包下都可以。
比如我們有一個類Animal在包org.example下,聲明了一個age字段:
package org.example;
public class Animal {
protected int age;
}
有一個類Duck繼承了這個類,它在org.example.duck下:
package org.example;
import org.example.Animal;
public class Duck extends Animal{
public int ageOfDuck(){
return age;
}
}
在Duck中是可以自由使用age字段的。
package-private與protected
這兩種權限很容易混淆,在使用時,可以分開來看。**兩種權限是互相獨立的,隻要滿足其中一條就可以通路到。**比如上文的類Animal,加了個字段:
package org.example;
public class Animal {
protected int age;
String name;
}
子類在org.example包裡面時,包權限生效,name可以被通路到,子類不在org.example裡面時,隻能通路到age。同一個包裡面的其他類,隻能通路到name字段。