访问控制(Access Control)
访问控制(或实现隐藏implementation hiding)
重写(rewrite)工作代码使其易读,易理解,好维护是重构(refactoring)代码的主要动力。
而面向对象设计主要考虑的是:“将会改变的东西与保持不变的东西区分开”
Java提供访问控制符(access specifiers)允许库的创建者指明什么内容客户程序员可以查看,什么不可以。
包(package):库单元(library unit)
一个包包含一组类,在单个namespace下组合在一起
import
用import可以导入单个类,例如:import java.util.ArrayList;
要导入所有内容,则用“”,例如:import java.util.;
之所以要用import导入,是为了提供一种特殊的机制以管理“命名空间(namespace)”。所有类成员的名字会相互隔离起来。类A中的方法f()不会和类B中完全相同(自变量列表)的f()冲突。可是类名却可能冲突,为了解决类名潜在的冲突,有必要对Java中的命名空间进行完整的控制,且需要创建一个独一无二的名字。
组织代码
为Java创建一个源码文件(source-code)的时候,通常叫做“编辑单元”(compilation unit)(有时也叫翻译单元(translation unit))。每个编译单元都必须有一个以.java结尾的名字。编译一个.java文件时,会获得一个名字完全相同的输出文件;但对于.java文件中的每个类,都有一个.class扩展名。最终从少量的.java文件里有可能获得数量众多的.class文件
在编译单元的内部,最多只能有一个(can only have one)公共(public)类,其必须名字必须和文件名相同(包括大小写,但排除.java的扩展名)
一个有效的程序就是一系列.class文件,它们可以封装和压缩到一个JAR文件里。Java解释器负责对这些文件的寻找、装载和解释
库也是由一系列类文件构成。每个文件都有一个public类和若干非public类。如果要将这些独自存在于各自.java和.class文件里的组件组织起来,那么package关键字的作用就很重要。
如果在文件的开头使用
package mypackage
package语句必须作为文件的第一个非注释语句出现。其作用是指出这个编译单元属于名为mypackage的库的一部分。或者说,它表明这个编译单元内的public类名位于mypackage这个名字之下
如果其他人 要调用这个名字,要么指出完整的名字,要么与mypackage联合使用import关键字
注意根据Java包(封装)的约定,名字内的所有字母都要小写
例如:
public mypackage
public class MyClass{
}
如果要使用MyClass,或MyClass下的其他public类,
i. 一种办法是指定完整的名称:
mypackage.MyClass m = new mypackage.MyClass();
ii. 另一种方法是使用import关键字
import mypackage
MyClass m = new MyClass();
要记住package和import关键字允许做的事就是分割单个全局命名空间(single global namespace)
独一无二的包名
按惯例,package名是倒过来的因特网域名(该域名可以是创建类的人自己的),这样package名肯定是独一无二的。
此外将package名解析成自己机器上的一个目录,这样Java程序需要加载.class文件时,就可以定位到.class文件所在的那个目录
Java解释器按如下步骤运行:
- 找到环境变量CLASSPATH,CLASSPATH包含一个或多个用来搜索.class文件的根目录
- 从该根目录开始,解释器获取包名,用斜杠替换点号,从而生成从CLASSPATH开始的一个路径名(例如包 foo.bar.baz 变成 foo\bar\baz或者foo/bar/baz)
- 之后将CLASSPATH路径和由包生成的路径连接(concatenated)在一起,成为CLASSPATH内的各个入口(this is concatenated to the various entries in the CLASSPATH),以后搜索.class文件时,就可以从这些地方查找与准备创建的类名对应的名字(也会搜索与Java解释器所在地方有关的标准目录)
见下例:
package com.bruceeckel.util;
public class Vector{
public Vecto (){
System.out.println(“net.mindview.simple.List”);
}
}
创建第二个文件:
package com.bruceeckel.util;
public class List{
public List(){
System.out.println(“com.bruceeckel.util.List”);
}
}
这两个文件都置于系统的一个子目录(subdirectory)中
C:\DOC\JavaT\net\mindview\simple
其中CLASSPATH,为:
CLASSPATH=.;D:\JAVA\LIB;C:\DOC\JavaT
可以看到,CLASSPATH能包含大量备用的搜索路径
正确设置好类路径后,可将下面这个文件置于任何目录中
package c05;
import com.bruceeckel.util.*;
public class LibTest{
public static void main(String[] args){
Vector v = new Vector();
List l = new List();
}
}
编译器遇到import后,会搜索CLASSPATH指定的目录,查找子目录com\bruceeckel\util,然后查找名称适当的已编译文件(对于Vector是Vector.class,对于List则是List.class)。
冲突
如果通过“”导入的两个库包含相同的名字?例如:
import net.mindview.simple.;
import java.util.*;
两个都含有Vector类,然而只有在新建Vector时才可能冲突:
Vector v = new Vector();
要新建则要具体指明:
java.util.Vector v = new java.util.Vector();
也可以只import要使用的类来避免冲突