我们可以把程序员划分为两大阵营:一是“类的创建者”(负责创建新数据类型的人),二是“客户程序员” (在自己的应用程序里使用现有数据类型的人)。客户程序员的诉求是收集一个装满了各种类的工具箱,以便自己能够快速开发应用程序。而类的创建者则负责在创建新的类时,只暴露必要的接口给客户程序员,同时隐藏其他所有不必要的信息。为什么要这么做呢?这是因为,如果这些信息对于客户程序员而言是不可见的,那么类的创建者就可以任意修改隐藏的信息,而无须担心对其他任何人造成影响。隐藏的代码通常代表着一个对象内部脆弱的部分,如果轻易暴露给粗心或经验不足的客户程序员,就可能在顷刻之间被破坏殆尽。所以,隐藏代码的具体实现可以有效减少程序bug。
所有的关系都需要被相关各方一致遵守的边界。当你创建了一个库,那么你就和使用它的客户程序员建立了一种关系。该客户程序员通过使用你的代码来构建一个应用,也可能将其用于构建成一个更大的库。如果一个类的所有成员都对所有人可见,那么客户程序员就可以恣意妄为,而且我们无法强制他遵守规定。也许你的预期是客户程序员不会直接操作任何类的成员,但是如果没有访问控制的话,你就无法实现这一点,因为所有的一切都暴露在对方面前了。
所以我们设置访问控制的首要原因就是防止客户程序员接触到他们本不该触碰的内容,即那些用于数据类型内部运转的代码,而非那些用于解决特定问题的接口部分。这种做法实际上为客户程序员提供了一种服务,因为他们很容易就可以知道哪些信息对他们来说是重要的,哪些则是无须关心的(请注意这也是一个富有哲理的决策。比如有些编程语言认为,如果程序员希望访问底层信息,就应该允许他们访问)。
设置访问控制的第二个原因则是,让库的设计者在改变类的内部工作机制时,不用担心影响到使用该类的客户程序员。例如,你为了开发方便而创建了一个简单的类,之后你发现必须重写这个类以提升它的运行效率。如果接口部分和实现部分已经被分离和保护起来了,那么你就可以轻松地重写它。
Java提供了3个显式关键字来设置这种访问控制,即public、private以及protected。这些关键字叫作“访问修饰符”(access specifier),它们决定了谁可以使用修饰符之后的内容。public表示定义的内容可以被所有人访问。private表示定义的内容只能被类的创建者通过该类自身的方法访问,而其他任何人都无法访问。所以,private就是一道横亘在你和客户程序员之间的高墙,任何人从外部访问private数据都会得到一个编译时报错。最后,protected类似于private,两者的区别是继承的子类可以访问protected成员,但不可以访问private成员。至于继承的概念,本书稍后会讲述。
如果你不使用上述任意一种访问修饰符,Java会提供一种“默认”访问权限,通常叫作“包访问”(package access),意思是一个类可以访问同一个包(库组件)里的其他类,但是如果从外部访问这些类的话,它们就像private内容一样不可访问了。