首先问一个问题,为什么要有访问控制权限?
安全,这当然是一个很重要的原因. 让类库的使用者只能接触他做需要接触的东西. 另外一方面,当我们去重构和修改代码的时候,如何不影响其他的代码和功能?权限访问控制是可以很好的将”变动的事物”和”不变的事物”区分开来.比如一个类库,在移除旧的实现添加新的实现的时候,很有可能会破坏客户端程序员的代码. 那么怎么办呢. 一个很好的思想就是,只暴露有必要的接口出去. 而屏蔽底层实现. 这些都是访问控制权限所需要做的事情.
简单来说,权限从大到小依次是,public,protected,default(包访问控制权限)和private.
包,package和import
同样的问题,为什么要有包?
- 提供唯一的名字空间,通过package,可以构建一个全球唯一的类,不用考虑名称空间的冲突
- 提供一种访问控制
通常的做法是将一些功能相似的类组织成一个package. package和import的作用就是将全局名字空间分割开来.
编译单元
一个.java的源文件通常被成为一个编译单元,一个编译单元内只能有一个public的类和0到任意个”非public”类. 其中public的这个类名字必须与文件名完全一毛一样.而其他非public的类,在这个package之外的世界是无法看到的. 它们的主要作用是用来为这个public类提供支持.
一个.java源文件”编译”后每个类都会生成一个.class文件. 按照编译型语言的剧本,之后这些中间文件会通过链接器或者类库产生器产生的其他同类文件捆绑在一起. 但是java不是编译型语言,所以java的做法是将这些.class文件打包成一个jar的文件. 运行的时候,由java解释器负责查找,装载和解释.
package创建规则
一个package不是将所打包的东西打包成一个单一的文件. 那么如何构建一个合理的package结构呢?java的做法是将package名字和.class文件的路径名字映射起来.
按照剧本,package名字的第一部分,是作者域名的反序书写. 比如我的域名是”thecatcher.net”(当然,由于当时租用的那个VPS性能太渣,这个网站已经挂掉了…) 那么我的包名称的第一部分就应该是net.thecatcher. 由于域名是全球唯一的,这一部分就已经保证了,你的package名称是独一无二的了. 第二部分就可以自定义了,爱啥啥. 映射到目录上,假设我有一个类net.thecatcher.demo.PackageDemo 那这个类的.class文件就应该存放在../net/thecatcher/demo/下
java解释器的运行过程
找环境变量中的CLASSPATH,并将CLASSPATH作为寻找的根目录,然后获取包名称,遇到.就转换成路径分隔符.以此作为类的路径去查找. 但是作为一个没有IDE连helloword都写不利索的水货,用eclipse的时候,这些事情就交给eclipse去处理了.
package和import
package没啥好说的,唯一需要注意的就是,这一语句必须出现在非注释行的第一行.
import有两个知识点:
第一,import static可以导入一个类中的所有静态成员(包括成员变量和成员方法),并合并到当前名称空间中.也就是说,可以少打几个字,直接调用方法就可以了,不需要再通过类名调用. 但是个人觉得,从代码可读性上说,这样并不好.
第二,可以通过import来改变代码的行为. java中没有条件编译,条件编译更多时候是为了平台移植. java不需要这个功能. 但是同时也失去了通过一个开关切换来产生不同行为的功能. 这时候有个好办法. 在debug的时候,两个类库功能一毛一样,但是一个是调试版一个是发布版. 可以在调用它的代码处通过更改package来进行切换.
比如,创建两个包,一个叫debug,一个叫debugoff. debug包中的代码包含一些可以显式发送一些消息到控制台,第二个没有这些东西. 那在调用这个类的类中,只需要通过切换不同的package就可以实现一键切换了.
权限修饰符
权限修饰符,public>protect>private
包访问权限
关键字default,但是一般不写的话默认就是包访问控制权限. 包访问控制权限允许将包内所有的相关类组合起来,使得他们可以轻松的访问. 包访问控制权限为把类聚集在一个包中的做法提供了意义和理由.
public:接口访问权限
为什么叫接口访问权限呢,想想也是,public的意义就是暴露出去给别人用,任何人都可以用. 正是接口的意义.
protected:继承访问权限
只有类内部和子类可以访问.
private
只有类内部可以访问.
接口和实现
访问控制权限的根本意义在于隐藏具体的实现,只暴露接口出去. 也就是所谓的封装. 访问控制权限将边界划在了数据类型的内部,限定客户端程序员可以使用和不可以使用的边界. 这样做是为了底层的安全. 另外以方便,将接口和具体实现相分离. 对上层调用来说,实现了底层无关.
类的访问权限控制
上面说的这些访问控制权限都是对类成员而言的. 而类也是有访问控制权限的. 类的访问权限修饰符只能是public或者default. 首先private是没有意义的. 给类上一个private,只有类内部可以访问,那要它干嘛? protected,类及子类可以访问. 如果继承了一个类,那么基类中的非private成员本来就是可以访问的. 那给它一个protected的权限同样没有意义.
那么如果想让一个类不能被随意的创建实例,可以通过私有化构造方法并且提供一个public的构建类实例的方法来实现. 比如单例模式.