7.3 访问权限
一个商业的Java应用系统有很多类,其中有些类并不希望被其他类使用。每个类中都有属性和方法,但是并不是所有的属性和方法都允许被其他类调用。如何能做到这样的访问控制呢?这就需要使用访问权限修饰符。
Java语言中的访问权限修饰符有4种,但却只有3个关键字。因为不写访问权限修饰符时,在Java中被称为默认权限(包权限),本教材中以default代替。其他3个访问权限修饰符分别为private、protected和public。
7.3.1 对类的访问控制
对于类而言,能使用的访问权限修饰符只有public和default。如果使用public修饰,则表示该类在任何地方都能被访问,如果不写访问权限修饰符,则该类只能在本包中使用。
继续上面的例子,将TestPackage.java文件中定义类的语句“public class TestPackage”中的public去掉,使该类的访问权限变为只能在本包中使用,再次编译TestPackage.java和TestImport5.java,在编译TestImport5.java时,编译器会报出如图7.7所示的错误。
7.3.2 对类成员的访问控制
对于类的成员(属性和方法)而言,4种访问权限修饰符都可以使用。下面按照权限从小到大的顺序对四种访问权限修饰符分别进行介绍。
1.私有权限private
Private可以修饰属性、构造方法、普通方法。被private修饰的类成员只能在定义它们的类中使用,在其他类中不能访问。
在第6章介绍封装的时候,已经使用了private这个私有的访问权限修饰符。对于封装良好的程序而言,一般将属性私有化,提供公有的getter和setter方法,供其他类调用。
下面构造方法私有化的问题。所谓构造方法私有化,就是说使用private修饰这个类的构造方法,如下所示。
package com.bd.test;
public class Student
{
String stuName; //学生姓名
//构造方法私有化
private Student(String name)
{
this.stuName = name;
System.out.println("学生姓名为:" + this.stuName);
}
}
使用下面的代码测试Student类,编译时报错,如图7.8所示。
import com.bd.test.*;
public class TestStudent
{
public static void main(String[] args)
{
Student wangYun = new Student("王云"); //使用构造方法创建学生对象
}
}
如果想在外部使用这个Student类,则只能在这个类内部实例化一个静态的Student类对象,并提供一个静态的、公有的方法获取这个类对象,具体代码如下。
package com.bd.test;
public class Student
{
String stuName; //学生姓名
static Student stu = new Student("王云");
//构造方法私有化
private Student(String name)
{
this.stuName = name;
System.out.println("学生姓名为:" + this.stuName);
}
//静态公有方法返回类对象
public static Student getStudent(){
return stu;
}
}
使用下面的代码获取Student类对象,程序可以正确运行。
import com.bd.test.*;
public class TestStudent2
{
public static void main(String[] args)
{
Student stu = Student.getStudent();
}
}
注意,此处Student类是一个单例模式的类。通过将构造方法私有化,使这个类的创建只能在类的内部完成,并且用一个公有的方法返回了这个类的实例。这样做可以保证这个类只有一个实例,不会出现其他类中为这个类创建多个实例的情况,这就是单例模式。
2.默认权限default
属性、构造方法、普通方法都能使用默认权限,即不写任何关键字。默认权限也称为同包权限。同包权限的元素只能在定义它们的类中以及同包的类中被调用。下面以普通方法为例介绍同包权限。修改Student类,代码如下。
package com.bd.test; //Student类在com.bd.test包中
public class Student
{
String stuName;
public Student(String name)
{
this.stuName = name;
}
//访问权限为default
void showName()
{
System.out.println("学生姓名为:" + this.stuName);
}
}
使用下面的代码测试调用Student类的默认访问权限的showName()方法。注意,两个类不在同一个包中,编译时报错,如图7.9所示。
//TestStudent3类在当前目录,不在com.bd.test目录中
import com.bd.test.*;
public class TestStudent3
{
public static void main(String[] args)
{
Student wangYun = new Student("王云"); //使用构造方法创建学生对象
wangYun.showName();
}
}
在void showName()方法前添加public关键字,编译并运行程序,可正常运行。
3.受保护权限protected
protected可修饰属性、构造方法、普通方法,能在定义它们的类中以及同包的类中调用被protected修饰的成员。如果有不同包中的类想调用它们,那么这个类必须是这些成员所属类的子类。关于子类及相关概念,将会在讲解继承的时候详细介绍。
4.公共权限public
Public可以修饰属性、构造方法和普通方法。被public修饰的成员,可以在任何一个类中被调用,是权限最大的访问权限修饰符。
7.3.3 访问权限修饰符总结
访问权限修饰符使用范围总结如表7.1所示。
修饰符 | 类内部 | 同一个包中 | 子类 | 任何地方 |
---|---|---|---|---|
private | Yes | |||
default | Yes | Yes | ||
protected | Yes | Yes | Yes | |
public | Yes | Yes | Yes | Yes |