包
包是Java语言中有效的管理类的一个机制。不同Java源文件中可能出现名字相同的类,如果想区分这些类,就需要使用包名。使用包名的目的是有效的区分名字相同的类。
1.包语句
通过关键词package
声明包语句。package语句需要放在Java源文件的第一条语句,指明该源文件定义的类所在的包,即为该源文件中声明的类指定包名。
一般格式:
package 包名;//包名是一个合法的标识符或者若干个标识符加“.”分隔而成
有的小伙伴可能会有疑问了,在这篇blog之前的blog中的Java代码都没有加上述语句,为什么还能运行?那是因为我们省略了package语句。如果省略了该语句,源文件中所定义命名的类被隐含地认为是无名包的一部分,只要这些类的字节码被存放在相同的目录中,那么他们就属于同一个包,只是没有包名罢了。
2.有包名的类的储存
如果我们显式地定义了包名,就不能再像之前那样在随意的位置存放了,需要遵守一定的规则,否则虚拟机将无法加载这样的类。
程序如果使用了包语句,例如:
package x1ao.lin;
那么在存储文件的目录结构中必须包含如下结构: .../x1ao/lin
(Windows下是\斜杠),并且要将源文件编译文件得到的字节码文件保存到该目录(源文件位置可任意)。
3.运行有包名的主类
如果主类的包名是x1ao.lin,那么主类的字节码一定一定要存放在.../x1ao/lin
目录中,因此必须到x1ao/lin
的上一层(即x1ao的父目录)目录中运行主类。举个栗子:
x1aolin@x1aolin-E402NA:~/projects$ java x1ao.lin.主类名
Notice: 运行时,必须写主类的全名。使用包名后主类的全名为“包名.主类名”。
举个栗子:
xueHao.java : 放在~/projects/x1ao/lin
文件夹下(ubuntu系统)
package x1ao.lin;
public class xueHao{
long xuehao;
xueHao(long xuehao){
this.xuehao = xuehao;
}
void print(){
System.out.print("学号为: "+xuehao);
System.out.print(" xueHao类: package x1ao.lin");
}
}
Exam2.java : 放在~/projects/x1ao/lin
文件夹下(ubuntu系统)
package x1ao.lin;
public class Exam2{
public static void main(String args[]){
xueHao number = new xueHao(2018061366);
number.print();
System.out.println("主类: package x1ao.lin");
}
}
- 编译。将这两个文件放入上面所述的位置后(这只是提供一种可能),然后进入到
/x1ao/lin
的上一层目录projects中编译两个源文件。如下图:
//其实只需要运行第一条命令即可,因为他们的源文件都放在同一目录中.
//只需编译主类的源文件,Java系统会自动地编译其他的源文件。
x1aolin@x1aolin-E402NA:~/projects$ javac x1ao/lin/Exam2.java
x1aolin@x1aolin-E402NA:~/projects$ javac x1ao/lin/xueHao.java
- 运行。在
x1ao/
的上一层目录运行
x1aolin@x1aolin-E402NA:~/projects$ java x1ao.lin.Exam2 //运行命令
学号为: 2018061366 xueHao类: package x1ao.lin //运行结果
主类: package x1ao.lin
注:java语言不允许用户使用java作为包名或者作为包名的一部分。
import语句
一个类可能需要另一个类声明的对象作为自己的成员或者作为方法中的局部变量。如果这两个类在同一个包中没问题,但是如果不再同一个包中,就需要import语句来进行引入了。
1.引入类库中的类
在编写源文件的时候,用户除了自己编写类外,经常使用Java提供的许多类,这些类可能在不同的包中。为了使用Java提供的类,可以使用import语句引入包中类。import语句可以有多个,位置需要放在package语句(可省略)和源文件类的定义中间。
- 如果要引入一个包中的所有类,可以用通配符“ * ”来代替。例如:
import java.util.*;
- 如果只是使用一个包中的某个类,就可以直接写明就可以了。例如:
import java.util.Scanner; //用于用户从控制台输入数据
举个详细的栗子给大家:
import java.util.Date;
public class Exam3{
public static void main(String args[]){
Date date = new Date();//这是Data类的构造函数
System.out.print("本地机器时间为:"); //不带空格
System.out.println(date);
}
}
运行结果如下,请大家自行体会:
x1aolin@x1aolin-E402NA:~/桌面/javaExample$ java Exam3
本地机器时间为:Wed Jun 13 13:00:24 CST 2018
下面给出两点说明:
- java.lang包是Java语言的核心类库,其中包含了运行Java程序必不可少的系统类,系统会自动引入,不需要再使用import语句。
- 如果使用import语句引入了整个包中的类,可能会增加编译时间,但是不会影响程序运行时的性能,因为运行和之和字节码有关。
2.引入自定义包中的类
方法一: 修改更新classpath,不推荐,此处也不再介绍,对此有兴趣的童鞋可自行百度。
方法二: 在用户程序所在的目录下建立和包相对应的子目录结构。
方法二该怎样理解呢?举个栗子,假定用户程序的某个类所在目录为~/java
,该类想使用import语句x1ao.lin包中的类,那么根据包名建立如下目录结构: ~/java/x1ao/lin
即可。emmmm…我个人的理解就是你可以自定义一个目录,然后一切活动都在这个目录下进行。如果定义一个包,就将包名形成的目录放在这个目录下按照一定的规则进行编译运行,不太会表达,大家可忽略这句话。
3.使用无包名的类
如果一个类想使用没有包名的类,只需要将这个无名包的类的字节码和当前类保存在同一目录下即可。(以前我们也是这么做的,有没有想起来呢_)。
4.避免类名混淆
- 如果一个源文件使用了一个无名包中的A类,同时又用import语句引入了某个有包名的同名类,比如
x1ao.lin
中的A类,这时候就会产生类名的混淆。 - 如果源文件明确引用该类:
import x1ao.lin.A;
当使用A类时,如果省略包名,那么源文件使用的是x1ao.lin
包中的A类,也就是说源文件无法使用无名包中的A类。如果想要同时使用,就不能省略包名了。系统会自动检测,如果检测到包名,就会自动判定省略包名的代码是使用的无名包。
举个栗子:
A x1 = new A(); //无名包创建的对象
x1ao.lin.A x2 = new x1ao.lin.A(); //指定包创建的对象
- 如果源文件不明确引用该类:
import x1ao.lin.*;
当使用A类时,如果省略包名,那么源文件使用的是无名包中的A类,而无法使用指定包中的A类。如果想要同时使用,就不应该省略。
- 如果一个源文件引入了两个包中同名的类,那么在使用类时,不允许 省略包名。