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 访问权限 - 图1
图7.7 在不同的包中使用默认类

7.3.2 对类成员的访问控制

  对于类的成员(属性和方法)而言,4种访问权限修饰符都可以使用。下面按照权限从小到大的顺序对四种访问权限修饰符分别进行介绍。

1.私有权限private

  Private可以修饰属性、构造方法、普通方法。被private修饰的类成员只能在定义它们的类中使用,在其他类中不能访问。

  在第6章介绍封装的时候,已经使用了private这个私有的访问权限修饰符。对于封装良好的程序而言,一般将属性私有化,提供公有的getter和setter方法,供其他类调用。

  下面构造方法私有化的问题。所谓构造方法私有化,就是说使用private修饰这个类的构造方法,如下所示。

  1. package com.bd.test;
  2. public class Student
  3. {
  4. String stuName; //学生姓名
  5. //构造方法私有化
  6. private Student(String name)
  7. {
  8. this.stuName = name;
  9. System.out.println("学生姓名为:" + this.stuName);
  10. }
  11. }

  使用下面的代码测试Student类,编译时报错,如图7.8所示。

  1. import com.bd.test.*;
  2. public class TestStudent
  3. {
  4. public static void main(String[] args)
  5. {
  6. Student wangYun = new Student("王云"); //使用构造方法创建学生对象
  7. }
  8. }
7.3 访问权限 - 图2
图7.8 对构造方法私有化的类进行实例化

  如果想在外部使用这个Student类,则只能在这个类内部实例化一个静态的Student类对象,并提供一个静态的、公有的方法获取这个类对象,具体代码如下。

  1. package com.bd.test;
  2. public class Student
  3. {
  4. String stuName; //学生姓名
  5. static Student stu = new Student("王云");
  6. //构造方法私有化
  7. private Student(String name)
  8. {
  9. this.stuName = name;
  10. System.out.println("学生姓名为:" + this.stuName);
  11. }
  12. //静态公有方法返回类对象
  13. public static Student getStudent(){
  14. return stu;
  15. }
  16. }

  使用下面的代码获取Student类对象,程序可以正确运行。

  1. import com.bd.test.*;
  2. public class TestStudent2
  3. {
  4. public static void main(String[] args)
  5. {
  6. Student stu = Student.getStudent();
  7. }
  8. }

  注意,此处Student类是一个单例模式的类。通过将构造方法私有化,使这个类的创建只能在类的内部完成,并且用一个公有的方法返回了这个类的实例。这样做可以保证这个类只有一个实例,不会出现其他类中为这个类创建多个实例的情况,这就是单例模式。

2.默认权限default

  属性、构造方法、普通方法都能使用默认权限,即不写任何关键字。默认权限也称为同包权限。同包权限的元素只能在定义它们的类中以及同包的类中被调用。下面以普通方法为例介绍同包权限。修改Student类,代码如下。

  1. package com.bd.test; //Student类在com.bd.test包中
  2. public class Student
  3. {
  4. String stuName;
  5. public Student(String name)
  6. {
  7. this.stuName = name;
  8. }
  9. //访问权限为default
  10. void showName()
  11. {
  12. System.out.println("学生姓名为:" + this.stuName);
  13. }
  14. }

  使用下面的代码测试调用Student类的默认访问权限的showName()方法。注意,两个类不在同一个包中,编译时报错,如图7.9所示。

  1. //TestStudent3类在当前目录,不在com.bd.test目录中
  2. import com.bd.test.*;
  3. public class TestStudent3
  4. {
  5. public static void main(String[] args)
  6. {
  7. Student wangYun = new Student("王云"); //使用构造方法创建学生对象
  8. wangYun.showName();
  9. }
  10. }
7.3 访问权限 - 图3
图7.9 默认权限包访问

  在void showName()方法前添加public关键字,编译并运行程序,可正常运行。

3.受保护权限protected

  protected可修饰属性、构造方法、普通方法,能在定义它们的类中以及同包的类中调用被protected修饰的成员。如果有不同包中的类想调用它们,那么这个类必须是这些成员所属类的子类。关于子类及相关概念,将会在讲解继承的时候详细介绍。

4.公共权限public

  Public可以修饰属性、构造方法和普通方法。被public修饰的成员,可以在任何一个类中被调用,是权限最大的访问权限修饰符。

7.3.3 访问权限修饰符总结

  访问权限修饰符使用范围总结如表7.1所示。

表7.1 访问权限修饰符总结
修饰符 类内部 同一个包中 子类 任何地方
private Yes
default Yes Yes
protected Yes Yes Yes
public Yes Yes Yes Yes