写在前面的话

访问控制的功能很明显:
通过访问(权限)控制符隐藏类中的具体实现。
不但将数据结构和对数据结构进行的操作进行封装;而且对封装后的成员通过访问控制符,该隐藏的隐藏,该暴露的暴露。达到访问的安全性、类的可维护性、类数据的完整性。
通过访问控制符可以实现良好的封装. 访问控制符与继承无关。
访问控制符:访问级别(public、protect、default(friendly)、 private)

同一类 同一包 不同包的同一子类 不同包的不同子类
public
protect
default
private

之前曾经介绍过类的封装
结合访问控制符, 大致可以通过下面的图示反映出一些特性:
理解Java的访问控制
下面的内容也与此密切相关

访问控制(或隐藏具体实现)概述

访问权限控制专注于类库的创建者(provider)和该类库的外部使用者之间的关系。
为类及类成员所遵守的界限。访问权限的控制常被称为是具体实现的隐藏

安全访问性(consumer访问的角度):provider的类或类成员,
允许哪些consumer可以访问(对这些consumer而言是,类库或类成员的不可变动部分),
不允许哪些consumer访问 (对这些consumer隐藏了具体实现,对这些consumer而言是类库或类成员的可变动部分);

可维护性(从provider修改的角度):provider对类或类成员的修改,
不需要修改哪些consumer(对这些consumer隐藏了具体实现,对这些consumer而言是类库或类成员的可变动部分),
需要修改哪些consumer(对这些consumer而言是,类库或类成员的不可变动部分)。
理解Java的访问控制
访问控制采用的方式:
1) 访问控制符:为类、类成员设置不同级别的访问控制符
2) 库单元(类库):创建类库。
库单元(类库)是一个逻辑概念,即相关类的集合。提供了一个访问库类的界限。物理上,在java中是使用操作系统的子目录来实现库的,是相关×××.class文件的集合;在.net中是使用操作系统的动态连接库文件来实现库的,是相关类的集合。

两类开发人员:
1) 类库开发人员:提供第三方类库,不提供源程序。应该严格地遵循访问控制规则。
2) 应用程序开发人员:具有开发的源程序,该源程序的开发可以不必严格地遵循访问控制规则。
理解Java的访问控制

访问控制的三个原因

理解Java的访问控制
讨论
对于C语言来说,C语言函数定义首先进行声明(都是public),然后再进行函数实现,对于函数的实现,它是被封装起来的,因而变得可维护与安全.
但是对于Java语言来说,:
在类中可以出现访问控制符的三处单元
1) 类的声明
2) 方法的声明
3) 字段的声明
对于方法而言,方法定义 = 方法声明 + 方法实现 这个是和C语言很相似的,
但是Java却比C语言多了类的声明和字段的声明,所以具备有更好的封装的条件,这里很自然而然地引入了访问控制符

1, 访问安全:对于类库和类的使用者而言,不可以访问(偷窥和篡改)

访问权限控制符控制该类的类名、方法名、字段名可以被哪些类的方法所访问(即该类的类名、方法名、字段名可以出现在哪些类的方法中);或者说不可以被哪些类的方法所访问。
可以使用户不要碰触那些他们不该碰触地部分,这些部分对于包、类的内部操作是必要的,但是它并不属于客户端程序员所需接口的一部分。
所以应该将包、类内部设计为外部可访问部分和不可访问部分。类的公共接口(API方法)是用户真正能够访问到的,所以这一部分在分析和设计上是决定该类是否正确的最重要的部分。
理解Java的访问控制

从×××.java源程序的可读性,可理解上,
1) 库中外部可访问的类(public),放于源程序的最上部
顺序:public类、默认friendly类
2) 类中外部可访问的成员,放于类的前部。
顺序:field、method
顺序(例如method):public成员、protected成员、默认friendly成员、private成员
优点:类的使用者可以从头读起,首先阅读对他们而言最为重要的部分(即publec成员,因为可以从.class文件外部调用他们),等到预见作为内部实现的非public成员时停止阅读。

2, 类可维护性(如何维护类),也是最重要的原因。对于类库和类的设计者而言

类的重构(即重写代码)是不可避免的。可以让库设计者可以更改类的内部工作方式,而不必担心这样会对客户端程序员产生重大的影响,客户端代码可以不必重构或重新编译。
所以应该将包、类设计为不可变动部分和可变动部分,使接口和实现被明确地隔离和加以保护。
如果类的某单元对访问类是隐藏的,则该单元的修改,对该访问类而言具有可维护性。

理解Java的访问控制

3, 数据的完整性

尽可能将field访问控制符设置为private,通过公共的getName()、setName()方法来访问。setName()方法中可以放置完整性规则,同时也具有可维护性。
理解Java的访问控制

访问权限控制符

狭义上访问通常指类声明的访问,和方法声明的访问。
(由于域定义总是private,方法的实现总是被隐藏)
理解Java的访问控制

1.类的访问权限控制符

类的访问,通常是指类声明的访问。
1)类的访问权限控制符:public
理解Java的访问控制
2) 类的访问权限控制符:默认friendly
理解Java的访问控制

3)类构造器的访问权限控制符:private,
a.可以阻止类外部直接创建该类的实例
b.可能将阻碍对此类的继承。
理解Java的访问控制
4)内部类的访问权限控制符:public、protected、默认friendly、private

2. 类成员的访问权限控制符:public、protected、默认friendly、private

由于域通常总是private,而方法的实现是被隐藏的;所以类成员的访问,通常是指对方法声明的访问(接口)
1)公共访问权限:public
理解Java的访问控制

2)子类访问权限:protected
与.NET的internal protected相同。
有两层含义:包访问权限或继承访问权
理解Java的访问控制
3)包访问权限:默认friendly
理解Java的访问控制
4)本类访问权限:private
理解Java的访问控制

3. 间接访问类成员

理解Java的访问控制


访问控制符使用原则

考虑到安全、可维护、完整性,尽可能使用低级别的访问控制符。
访问控制符从高到低的级别(范围):public、protected、默认friendly、private。
应尽可能地总是将字段指定为private,减少类间耦合;否则,将产生高耦合,数据结构的耦合不具有可维护性。
类中的方法实现与访问控制符无关,总是隐藏的,具有可维护性。

程序1:
包的可见性是public

package p1;
public class MyClass1 {
	public int a = 5;
	private int b = 10;
	protected int c = 20;
	int d = 30;
	public void func1() {
		System.out.println("func1");
	}
	private void func2() {
		System.out.println("func2");
		System.out.println(b);
	}
	protected void func3() {
		System.out.println("func3");
	}
	void func4() {
		System.out.println("func4");
	}
}

程序2:
包的可见性是默认friendly

package p1;
class MyClass2 {
	public void func1() {
		System.out.println("func1 of MyClass2");
	}
}

程序3
同包内访问
同包指MyClass1类、MyClass2类和Test类的包名相同,逻辑上在一个包内。
并不要求MyClass1类文件、MyClass2类文件和Test类文件一定在同一个子目录中。

package p1;
public class Test {
	public static void main(String[] args) {
		MyClass1 obj1 = new MyClass1();
		//a是公共属性,任何地方都可以访问
		System.out.println(obj1.a);
		// Error,b为私有属性,类外无法访问
		//System.out.println(obj1.b);
		// c是受保护属性,同包的类可以访问
		System.out.println(obj1.c);
		// d是缺省属性,同包的类可以访问
		System.out.println(obj1.d);
		// func1()是公共方法,任何地方都可以访问
		obj1.func1();
		//Error,func2()为私有方法,类外无法访问
		//obj1.func2();
		// func3()是受保护方法,同一包中的类可以访问,其他包中的子类也可以访问
		obj1.func3();
		// func4()是缺省方法,同一包中的类可以访问
		obj1.func4();
		// 同一包中的缺省访问控制类可以访问
		MyClass2 obj2 = new MyClass2();
	}
}

程序4:
不同包间非继承访问

package p2;
import p1.MyClass1;
//Error,不能导入不同包中的缺省类
//import p1.MyClass2;

public class Test {
	public static void main(String[] args) {
		MyClass1 obj1 = new MyClass1();
		// 公共属性,任何地方都可以访问
		System.out.println(obj1.a);
		// Error,b为私有属性,类外无法访问
		//System.out.println(obj1.b);
		// Error,c是受保护属性,不同包中的非子类无法访问
		//System.out.println(obj1.c);
		// Error,d是缺省属性,不同包中的类不能访问
		//System.out.println(obj1.d);
		// func1()是公共方法,任何地方都可以访问
		obj1.func1();
		// Error,func2()为私有方法,类外无法访问
		//obj1.func2();
		// Error,func3()是受保护方法,不同包中的非子类无法访问
		//obj1.func3();
		// Error,func4()是缺省方法,不同包中的类不能访问
		//obj1.func4();
		// Error,不可以访问不同包中的缺省类
		//MyClass2 obj2 = new MyClass2();
	}
}

程序5:
不同包间继承访问

package p3;

import p1.MyClass1;
//Error,不能导入不同包中的缺省类
//import p1.MyClass2;

public static void main(String[] args) {
	public void func() {
		// 公共属性,任何地方都可以访问
		System.out.println(a);
		// Error,b为私有属性,类外无法访问
		//System.out.println(b);
		// c是受保护属性,子类可以访问
		System.out.println(c);
		// Error,d是缺省属性,不同包中的类不能访问
		//System.out.println(d);
		// func1()是公共方法,任何地方都可以访问
		func1();
		// Error,func2()为私有方法,类外无法访问
		//func2();
		// func3()是受保护方法,子类可以访问
		func3();
		// Error,func4()是缺省方法,不同包中的类不能访问
		//func4();
		// Error,不可以访问不同包中的缺省类
		//MyClass2 obj2 = new MyClass2();
	}
}

相关文章: