建立Java包,布局源文件和设置classpath参数之间相互影响。也相互关联。正确建立和导入JAVA包,合理布局源文件,准确设置CLASSPATH参数,才能保证应用程序顺利执行,并有效管理应用程序。
包的建立方法
Java包通过package语句建立,基本语法是:
package cn.edu.jmu.graphis;
在定义类或接口的源文件开始处,通过package语句,可以将相应的类或接口放入package所声明的包里。包是相关类和接口的集合,提供了访问级别控制和命名控件管理。
包的使用方法
每个源文件只能有一个包声明,并且一定要求放在源文件的开始位置。如果一个源文件没有包语句,则源文件所定义的类或接口呗系统放入默认包中。包有层次,层次间由点分隔。
例如有一组与图形相关的类,包括Circles,Rectangles,Lines和points类等,描述了画图所用到的各种图形组件,另有抽象类Graphic标识图形组件的共性,接口Draggable表示用户可以通过鼠标拖拽成图的图形组件。在这种情况下,我们不仅需要,而且也应该将这些相关类和接口组成包,可命名为graphics如:
//Graphics.java
package graphics;
public abstract class Graphic{
...
}
//Circle.java
package graphics;
public class Circle extends Graphic implements Draggable {
...
}
//Rectangle.java
package graphics;
public class Rectangle extends Graphic implements Draggable {
...
}
//Draggable.java
package graphics;
public interface Draggable{
...
}
通过创建和使用包,程序员不仅可以很容易地确定哪些类和接口是相关的,也可以很容易地找到提供特定功能的类和接口,例如,与画图有关的类和接口在graphics包中。
包的访问权限
通过声明类的访问级别,可以控制对类的访问权限。
类的访问级别分为默认级和public级。定义类的默认访问级别不需要任何关键字,呗声明为默认级的类只对同一个包中的类是可视的。也就是说只有同一个包内的类实例可以访问这个类,外界不能访问它。如果用关键字public定义类,不但同一个包里的其他类可以访问这个类,其他包中的类也可以访问它。换句话说,同一个包中的类,相互之间有不受限制的访问权限。而在不同包中,只有public类可以被访问。
public修饰符不知用于定义类的访问控制级别,也可以应用于接口,方法或变量。public 接口同public类一样,可以由应用程序中的任何类访问。而public方法或public属性对任何可以访问他的类或接口都是可视的。
除public修饰符之外,用于访问控制的修饰符还有protected 和 private。
protected 或 private 仅用来定义方法或变量的访问控制级别。protected 方法或protected变量仅对同一个包内的类或不同包中的子类来说是可视的。
private方法和pvivate变量对外部定义的类均不可视。
包的命名方式
包提供了心的命名控件,即使所定义的类使用与其他包中的类相同的名字,只要包类所属的包不同名,就不会引起冲突。原因是这些类的全程限定名称不同。类的全程限定包含了类的各层包名。这实质上是应用了面向对象的概念,将类封装入包中。
包的访问权限
通过声明类的访问级别,可以控制对类的访问权限。
类的访问级别分为默认级和public级。定义类的默认访问级别不需要任何关键字,贝声明为默认级的类只对同一个包中的类是可视的。也就是说,只有同一个包内的类实例可以访问这个类,外界不能访问它。如果用关键字public 定义类,不但同一个包里的其他类可以访问这个类,其他包中的类也可以访问它。换句话说,同一个包中的类,相互之间有不受限制的访问权限。而在不同的包中,只有public类可以被访问。
public 修饰符不只用于定义类的访问控制级别,也可以应用于接口,方法和变量。public接口同public类一样,可以由应用程序中的任何类访问。而public方法或public变量对任何可以访问他的类或接口都是可视的。
除public 修饰符之外,用于访问控制的修饰符还有 protected 和private 。 protected或private仅用来定义方法或变量的访问控制级别。protected方法或protected变量仅对同一个包内的类或不同包中的子类来说是可视的。private方法和private变量对外部定义的类均不可视。需要说明的是,通常不建议用默认方式定义方法或成员变量的访问级别。
对于没有指定包名的java源文件,系统认为他们都属于同一个默认的包。如果没有把自己的Java类放入某个包中,那么任何默认包里的对象都可以访问它,并且不局限于同一个子目录下,因此通常应该在每个Java源文件的项目顶部使用 package语句,指明它所属的包。
访问包成员
对于包来说,只有它的public成员可贝外界访问。若外界想要访问包的public类,有3种方式可以实现。
(1)通过类的全程限定名访问该类。
(2)通过import语句导入该类。
(3)通过import语句导入整个包。
如果某个类只贝访问一次,那么可以直接使用类的全名。例如访问cn.edu.jmu.graphics.Graphic类可以用一下方式:
cn.edu.jmu.graphics.Graphic aGraph = new cn.edu.jmu.graphics.Graphic();
这条语句创建了 cn.edu.jmu.graphics.Graphic类型的对象 aGraph。
可以看到,即是指创建一个对象,在变量定义和初始化时也用到两次全名。当使用Java约定的包命名方式时,包名可能过长,此时用起来就更显得繁琐,容易出错,也影响可读性。
通常都应该使用import语句直接导入所需类,或者导入该类所在的包。导入之后,程序中设计的这个类的地方就可以直接用类名访问。
import 的基本语法形式为:
import <包名>[.<子包名>].<类名>; //导入指定类
或者:
import <包名>[.<子包名>].*; //导入整个包
例如:
import cn.edu.jmu.javaprogs.Timel;
import cn.edu.jmu.javaprogs.*;
import java.awt.*;
import java.awt.event.*;
import语句在package 语句之后,所有的类声明之前。由于集中在程序首部,宜于直观地了解程序所需的包,有助于维护程序的可移植性。
import 语句中的 * 用来匹配包中的所有类,但并不能用来匹配包中的所有类的某个子集。如语句
import java.awt.*;
导入java.awt包中的所有类。如果这样的语句
import java.awt.A*;
它无法导入java.awt句中首字母为A的所有子类,相反还会出现编译错误,也就是说,使用import语句一次只能导入包的单一成员,或者导入整个包。
还有语句
import java.awt.*;
所导入的是java.awt包中的所有类,它包括接口。但不包括java.awt包中的子包。如果需要访问java.awt.event子包中的类,仍需要用 import语句导入 java.awt.event子包。所以常常使用如下形式:
import java.awt.*;
import java.awt.event.*;
包的布局
类的全程受名称与类所在目录一一对应,例如:
import graphics.Rectangle 等同于文件路径名:
Graphics\Rectangle.java
classpath参数
classpath参数用于设置Java包所在的顶级目录。也就是说,通过classpath可以为Java包建立所依存的目录列表。编译和运行Java 程序时,系统会自动从classpath环境变量中读取包所在的目录,文件所在目录由系统通过classpath中的目录和package语句中定义的目录合成。
下面通过一个完整的实例程序,说明classpath参数的作用,同时展示源文件和字节码文件的一种建议布局模式。
程序包含两个类 Time 和 TestTime,TestTime为主类。程序对用户输入的表示小时、分钟和秒钟的3个整型数,经过数据正确性验证,分别转换为通用时间表示格式和标准时间表示格式,通过对话框显示给用户,运行后如图:
文件布局方式如下:创建 d:\javaSample 目录存放java程序,创建 d:\javaSample\src 子目录存放源文件,创建d:\javaSample\class 子目录存放编译后的字节码文件。 具体实现方式是将文件 TestTime.java 存放在 D:\javaSample\src 子目录下,为使 src 子目录的结构与 class 子目录结构相对应,创建 D:\javaSample\src\cn\edu\jmu\timer 子目录存放 Time.java文件。类Time和类TestTime的布局如图:
Time.java中的语句
package cn.edu.jmu.timer;
将Time类放入包cn.edu.jmu.timer中,源文件Time.java存放在与包相对应的目录结构下。在类TestTime.java中通过语句 import cn.edu.jmu.timer.Time; 导入Time类。
需要设置classpath参数,规定程序中的包 cn.edu.jmu.timer 编译所依存的顶级目录为 d:\javaSample\class,如:
set classpath = d:\javaSample\class;
编译:
javac -d d:\javaSample\class
d:\javaSample\src\cn\edu\jmu\timer\Time.java
javac -d d:\javaSample\class d:\javaSample\src\TestTime.java
运行:
java TestTime