在一个Java工程中,往往会包含很多类。为了方便工程管理,程序员总是希望能够把这些类按照功能分开存放。为了达到这个目的,Java语言允许开发者把不同的类放入不同的包中。所谓“包”就是存放类的容器,在一个包中可以存放多个类。
程序员使用IDEA可以很轻松的创建出一个包,其过程如图6-8所示。
图6-8 创建包
首先选中工程的源代码文件夹src,然后单击右键,从弹出的菜单中选择New->Package,单击Package菜单项后,会弹出填写包名的对话框,如图6-9所示。
图6-9 设置包名称
在这个对话框内,只需在文本框中填写包名,然后按下回车键即可完成包的创建。按照命名习惯,包都会以纯小写英文进行命名,并且尽量做到“见名知意”。一个包的内部还可以出现其他的包,外层包和内层包之间都会使用“.”作为分隔。 例如图6-9中创建了一个叫做a的包,如果在a包中还想创建一个名叫a1的内层包,仍然是在右键菜单中选择New-> Package,然后在弹出的填写包名对话框中写上“a.a1”即可。
如果希望把一个类创建到某个包中,可以先从IDEA中选中这个包,然后单击右键,在右键菜单中选择“New”->“Java Class”即可,如图6-10所示。
图6-10 在包中创建类
当一个类处于某个包当中,这个类的最上方都会通过package关键字显示出它所在包的名称。例如,在a包中创建一个A类,在A类的最上方就会显示:
package a;
把包的名称显示在类的最上方,可以标识出这个类的出处。这样虚拟机既可以通过包名找到这个类,也可以根据包的名称区别两个同名类。Java语言规定:如果两个类位于同一个包中,那么这两个类不能同名,但是如果两个类不在同一个包中,那么它们的名称可以相同。虚拟机就是根据不同的包名来区分两个同名类。
在Java语言中,在一个类中如果需要用到一个不同包中的类,必须先对这个类完成引入操作。完成引入操作需要用到import关键字。例如在前面的章节中引入用于接收键盘输入的Scanner类需要用如下语句实现:
import java.util.Scanner;
如果没有用import关键字引入其他包中的类,那么在使用这个类的时候就必须把它的包名一起写出。例如,在没有引入Scanner类的情况下,如果要创建一个Scanner类,就必须按以下方式书写代码:
java.util.Scanner sc = new java.util.Scanner(System.in);
需要提醒各位读者:两个类如果位于相同的外层包,但不在同一个内层包时,这两个类不属于同一个包。例如Scanner类和Math类,分别位于java.util包和java.lang包,虽然外层包都是java,但它们分属于util和lang两个内层包,因此,Scanner类和Math类不能算做同一个包中的类。
在日常开发过程中,程序员对java.lang包中的类使用频率非常高,几乎每编写一个程序都要用到java.lang包中的类,例如表示字符串的String类和用于打印操作的System类等。为了简化操作,编译器对java.lang包做了特殊处理,它允许程序员在使用java.lang包中的类时不进行手动引入,这就是为什么在所有程序中从未引入String类和System类的原因。事实上,编译器会在编译代码阶段自动把引入java.lang包中类的语句添加到程序中。
使用import关键字还可以一次性引入一个包中所有的类,此时只要把语句中的类名称替换为*即可。例如想要一次性引入java.util包中所有的类,就可以用以下语句实现:
import java.util.*;
这种引入方式可以在很大程度上减少代码量。例如在编写操作数据库的代码时,需要用到多个来自于java.sql包中的类,为了减少引入类的代码量就可以采用一次性引入的方式完成编码。此处还需要提醒各位读者:一次性引入某个包中所有类,并不会引入这个包的任何一个内层包中的类。例如:a包中如果还有一个a1内层包,语句“import a.*;”仅能够把直接位于a包中的类引入程序,而不会把内层包a1下的任何一个类引进来。
由于Java语言允许不同包中的类使用相同的名称,这就导致引入同名类会出现语法错误。例如在java.util包和java.sql包当中都有一个叫做Date的类,如果程序中同时引入这两个类就会引起语法错误,如图6-11所示。
图6-11 引入同名类导致语法错误
之所以出现语法错误,就是因为在实际使用Date类的时候,虚拟机无法分辨这个Date类到底来自于哪一个包。但实际开发过程中,在同一个程序中使用两个同名类的情况根本无法避免。为了解决这个问题,可以在程序中去掉引入这两个类的语句,改为把类前面加上包名的写法。例如,想要创建来自不同包中Date类的对象,可以按照如下方式编写代码:
- java.util.Date d1 = new java.util.Date(0);
- java.sql.Date d2 = new java.sql.Date(0);
在类的名称前面加上完整的包名,就能清楚的区分两个同名类,从而解决了同名类同时出现在一段代码中的问题。