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
字段。