从零学Java(8)——访问控制权限
不得不吐槽一下,几天前更新了篇博文,结果push到github上就一直报错,提示还是一些很早的文章有错误。刚开始还能找到原因,主要是一些html语句被禁用了(难道jekyll更新了?),再后来的提示根本就不知道错误在哪里。后来感觉是电脑上的ruby版本太低,就安装了一个ruby1.9.3,但是jekyll好像不能识别用源码安装的ruby,尽管ruby -v显示的是1.9.3的版本,但是使用rvm就会显示1.9.1。没办法,用rvm来安装ruby吧,结果还报错,说libyaml没有安装。其实已经安装了,但是还是没有识别的问题。好吧,那就安装libyaml。用rvm或brew安装,会报错(也找不到哪里错误),用源码安装,结果提示缺少一些东西。那感觉像是编译器的问题,好吧,又要下载编译器,但是brew下载gcc的新版本又提示错误(编译出错)。没办法,更新xcode5,使用它提供的command line tools吧,2个多G啊。。。终于熬完了,结果还是不行。安装command line tools,发现xcode上还没有显示哪里安装。发现可以输入命令安装,结果安装不成(又不知道是哪里错误),那申请苹果的developer,从网上下载dmg文件安装吧,安装完后还是不成。怒了,卸载brew重新安装,结果网还被墙了。。。安装macports,再安装gcc,等了若干时间,又报错。终于,发现自己陷入了死循环。
解决办法是,把github上的repo删除,重新把jekyll下下来,再把之前的配置、文章和图片加入里面,别说,还真成功了。
现在越来越发现,折腾jekyll真是件头疼的事情,而操作系统本身也各种添堵(怀念起使用ubuntu的日子,那才叫便捷啊)。差点就放弃换个博客系统了。幸亏最终解决了问题。
这篇博客对应于《Java编程思想》第6章。什么是”访问控制权限“?打个比方,你不想让别人动你家的东西,那就用private,你想让别人用你家的东西,就使用public,你仅仅想让你和你的子女(即继承)用你家的东西,但不希望这个”大家庭“之外的人用,那就用protected。其实还有个包访问权限,它没有关键词。这个后面再说。说白了就是在设置作用域,对于设计类的程序员,当然希望能够使用类中任意的元素。而对于用户,类的设计者可能更希望他们仅仅使用类提供的接口,而不是使用内部的元素,防止出现错误,或破坏了封装。
这里需要介绍一个概念,包。比如你写了一个类A,但是有一个与类A同名的类,这时”包“就起到作用了。我们将这些构建设置到同属于某一个组群中,来解决冲突。比如你写了很多Java源文件,你想把这些源文件构建为同一个组群(包),就使用如下方法:
package access;
比如这些文件属于/access/mypackage文件夹内,则:
package access.mypackage;
如果要使用这个包中的类,我们这样做:
import access.mypackage.object;
我们看到了,引入时的这些”.“就是路径分隔符。object是类的名字,当然也可以引入所有的类。这样做既可以防止冲突,又方便使用这些类。
在Eclipse中,可以直接创建package,然后添加代码即可。而如果是在命令行输入命令来执行Java,就需要设置CLASSPATH(《从零学Java——搭建编程环境》这篇博文中,我们设置过这个环境变量,当时还不知道有什么用),这个变量帮助Java虚拟机找到你放包的位置。
前面说过包访问权限,包访问权限不需要任何关键字(有时也表示为friendly),意味着当前的包中的所有其他类对那个成员都有访问权限,但对于这个包之外的所有类,这个成员却是private。即处于同一个编译单元中的所有类彼此之间都是自动可访问的。如果处于相同目录且没有设定任何包名称的源代码,Java将其自动看作是隶属于该目录的默认包之中,于是它们为该目录中所有其他的文件都提供了包访问权限。
对于关键字public,它声明的所有成员对每个人都是可见的。但需要注意,每个Java源程序都仅能有一个public类,且这个类名称必须与文件名完全匹配。编译单元(源代码)中也可以不带有public类(不常用)。此时可以随意命名文件名。
private的作用使得除了包含该成员的类之外,其他任何类都无法访问这个成员。private有个特殊的用法,即它可以控制如何创建对象,并阻止别人直接访问某个特定的构造器(或全部构造器)。
class A {
private A {}
static A makeA() {
return new A();
}
}
public class B {
public static void main(String[] args) {
A x = A.makeA();
}
}
我们看到,由于私有化了A类的构造器,我们只能通过makeA()类来创建A类对象。我们发现,这个A类是不能被继承,因为初始化导出类时,自动先处理基类的初始化。由于基类的构造器被设置为private,导出类无法访问,故初始化会失败。
在书中122页中提到了一种类似的用法:
class Soup2{
private Soup2() {}
private static Soup2 ps1 = new Soup2();
public static Soup2 access() {
return ps1;
}
}
该用法是设计模式的一种——singleton单例,你始终只能创建它的一个对象,并且只能通过access方法来创建。我们来思考一下,为什么实现该功能要如此做。首先构造器一定要设置为private,否则构造器便可以任意使用。构造器也没必要设置为static类型(默认的static类型)。接下来我们想要只能创建该类的一个对象,这时比较直观的想法就是使用静态域,使得无论创建多少对象,都只存在一个该对象的拷贝。单单设置为static类型还不够,因为我们希望能够不直接创建这个对象,而是通过其他方法来创建。所以我们设置access方法并返回这个对象的引用。
如果知道继承,protected就很好理解。我们将基类中的成员或方法设置为protected,此时只有该基类或其导出类才能使用这个成员或方法。
通过访问控制权限,我们不仅能够设置内部的权限机制,防止用户误将内部方法或成员当做接口。而且,我们还实现了接口与具体实现的分离,防止用户对类中具体实现的修改或破坏。
blog comments powered by Disqus