2.4 Java源文件结构
Java语言的源程序代码由一个或多个编译单元(Compilation uni t)组成,每个编译单元只能包含下列内容(空格和注释除外),如表2-1所示。
表2-1 Java源文件结构
注意:
(1)需要特别注意的是, Java是严格区分大小写的。
(2)定义为public的类名必须与Java文件名称完全一致,每个Java源文件只能有一个定义为public的类,但可以有几个非public的类名。
2.4.1 知识准备:package语句
在大型项目开发中,为了避免类名的重复,经常使用“包”来组织各个类。例如,公司用开发了一个类Food,公司乙也开发了一个类Food,现在需要同时用到这两个类,为了将这两个类区分开来,将这两个文件放在两个不同的目录下。那么,在使用的时候如何准确地找到需要的类呢?这就需要用到“包(package)”这个概念。
在Java程序中可以用package来指明这两个类的引用路径:将甲公司开发的Student类放到一个包(package)中,而将乙公司开发的Student类放到另一个包(package)中。为了避免不同的公司之间类名的重复,Sun建议使用公司Internet域名的倒写来当做包名,例如,使用域名 farsight.com.cn的倒写 cn.com.farsight来作为包的名称。如果现在有一个名为Student的类,将它放到目录cn\com\farsight下,然后再在程序中加入如下语句:
package cn.com.farsight;
这样,这个类就可以和其他的名称为Student的类区分开了。
package语句的基本语法如下:
package <top_pkg_name> [ .<sub_pkg_name>] * ;
在同一个项目组中,经常用功能或模块的名称来作为子包名,例如,现在开发一个学员管理系统,一个用于华清远见的管理模块,一个用于清华附中的管理模块,这两个功能模块中均有一个Student的类,这时可以将华清远见管理模块中使用的Student 放到cn\com\farsight\college目录下,而将清华附中管理模块的Student类放到cn\com\farsight\school中,这样,这两个文件就不会冲突了。
注意,当将开发的类放到包中时,必须将类的源文件放到与包名的元素相一致的目录结构中,就如上面的学生类 Student,如果在文件中加入了package语句:package cn.com.farsight,则必须将这个Student类文件放到cn\com\farsight目录下。在磁盘目录结构中,使用“\”(Windows)或“/”(Unix/Linux/BSD)来分隔各个层级的目录,而在Java类文件中,使用“.”来分隔包的层次。
Java的核心包都放在Java包及其子包中,而将很多扩展包放在javax包及其子包中。在Java 核心包中,也有一些重复的类名,就是通过不同的包来区分的,例如,在java.sql包中,有一个Date类,而在java.util中,也有一个Date类。通过将它们放在不同的包中,就可以区分这两个类。
一般来说,如果在程序中使用package 将程序打包,则将程序放到对应的目录下,这样,才不违背package的设计初衷。如果将类的源文件(.java文件)都放到同一个路径下,只是将编译后的class文件放到不同的目录下,上面提到的文件名冲突的问题依然存在(同一个路径下不允许两个文件同名),因此,需要将源文件保存在不同的路径中。这时,可以使用如下命令来编译文件:
javac cn\com\farsight\college\Student.java
在cn目录的上一级目录下执行上述命令。
如果程序是一个带main方法的应用程序,可以在cn目录的上一级目录下执行这个文件,命令如下:
java cn.com.farsight.college.Student
注意编译和执行时的分隔符。因为在编译时,需要指明的是文件的路径,所以使用“\”来分隔;而在执行类文件时,需要指明的是包名称,所以使用“.”来分隔。
下面来看一个使用package的例子。
源文件:Student.java
package cn.com.farsight; public class Student { // 定义属性 private String studentId; // 定义属性“studentId”的设置方法 public void setStudentId(String student_Id) { studentId = student_Id; } // 定义属性“studentId”的获取方法 public String getStudentId() { return studentId; } }
这个程序最好放在路径cn\com\farsight下,然后再在cn的上一层路径执行如下的指令编译程序:
javac cn\com\farsight\Student.java
而被编译后的class文件必须放置在cn\com\farsight路径下,这样才可以成功地被其他程序引用。
如果Student是一个应用程序(有一个main()方法),那么,为了执行这个程序,必须在“cn”的上一级目录执行如下的指令:
java cn.com.farsight.Student
2.4.2 知识准备:import语句
在编译器定位你所创建的类所访问的其他类的过程中,包(package)扮演了重要的角色。当编译器碰到一个类对另一个类的引用时,它会在当前的包中和设置的CLASSPATH中寻找这个类,以检查这个类是否能在这些路径中找到。
import语句应该出现在package语句之后(如果有的话),类的定义之前。package语句只能有一个,但是import语句可以有多个。
可以使用import来引入包中的一个类,也可以用import来引入指定包中的所有类。
import语句的基本语法如下:
import <pkg_name>[.<sub_pkg_name>].<class_name>;
或
import <pkg_name>[.<sub_pkg_name>].*;
□引入一个类:
import cn.com.farsight.college.Student
□引入指定包中的所有类使用通配符“*”:
import cn.com.farsight.college.*
这样就可以引入包cn.com.farsight.college中的所有类。
这两种方式对于引入相应的类并没有什么区别。但是,如果只是需要一个包中有限的几个类,建议采用第一种方式(写明引入的类名)会让人一目了然。另外,需要注意的是,通过import引入包中的类的时候,它并不会递归地执行引入动作,比如,通过下面的语句:引入了cn.com.farsight 这个包中的所有类,但它并不会引入cn.com.farsight.school和cn.com.farsight.colleage中的类。要使用这两个包中的类,还需要将它们使用“import”语句分别引入。
import cn.com.farsight.*;
Java编译器默认为所有的Java程序引入了JDK的java.lang 包中所有的类(import java.lang.*;),其中定义了一些常用类:System、String、Object、Math等。因此可以直接使用这些类而不必显式引入。但使用其他非无名包中的类则必须先引入、后使用。
另外,可以通过在类名前加上不同的限制符,如public等来控制类的适用范围。关于这些限制符及相应的使用范围,将在后续章节介绍。
注意:
使用import并不会将相应的类或者包加载到class文件(或者Java源文件),也不会包含到Java源文件(或者class文件)中,它的作用仅仅是对需要用到的类进行定位(location)。它表示程序中用到某个类的时候,如果没有在类前指定包名,应该到当前目录或者import指定的包中去寻找(注意java.lang包是默认引入的)。
2.4.3 任务二:package语句和import语句实例
1.任务描述
编写一个Parent类,在构造方法中输出“我是parent”,放在parent 包中,编写一个Child类,在构造方法中输出“我是child”放在child包中,child包是parent包的子包。使用package语句生成包,并使用import引用子包。
2.技能要点
□ 掌握包的创建和使用。
□ 通过给包命名创建包的层次。
3.任务实现过程
(1)在scr默认包中创建parent包,在此包中创建Parent类,不带参数,在构造方法中输出“I am a parent”。
(2)创建parent的子包parent.child包,在此包中创建Child类,不带参数,在构造方法中输出“I am a child ”。
(3)在Parent类中使用import语句引入parent.child包,并创建Parent类和Child类对象,实现输出。
Parent.java package parent; import parent.child.Child; public class Parent { public Parent(){ System.out.print("I am a parent"); } public static void main(String[] args) { Child c = new Child(); Parent p = new Parent(); } } Child.java package parent.child; public class Child { public Child(){ System.out.print("I am a child \n"); } }
运行结果:
I am a child I am a parent