package、import
Java定义了一种名字空间,称之为包:package
。一个类总是属于某个包,类名(比如Person
)只是一个简写,真正的完整类名是包名.类名
。
例如:
-
小明的
Person
类存放在包ming
下面,因此,完整类名是ming.Person
; -
小红的
Person
类存放在包hong
下面,因此,完整类名是hong.Person
; -
小军的
Arrays
类存放在包mr.jun
下面,因此,完整类名是mr.jun.Arrays
; -
JDK的
Arrays
类存放在包java.util
下面,因此,完整类名是java.util.Arrays
。
在定义class
的时候,我们需要在第一行声明这个class
属于哪个包。
小明的Person.java
文件:
package ming; // 申明包名ming
public class Person {
}
小军的Arrays.java
文件:
package mr.jun; // 申明包名mr.jun
public class Arrays {
}
在Java虚拟机执行的时候,JVM只看完整类名,因此,只要包名不同,类就不同。
包可以是多层结构,用.
隔开。例如:java.util
。
要特别注意:包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系。
没有定义包名的class
,它使用的是默认包,非常容易引起名字冲突,因此,不推荐不写包名的做法。
我们还需要按照包结构把上面的Java文件组织起来。假设以package_sample
作为根目录,src
作为源码目录,那么所有文件结构就是:
package_sample
└─ src
├─ hong
│ └─ Person.java
│ ming
│ └─ Person.java
└─ mr
└─ jun
└─ Arrays.java
即所有Java文件对应的目录层次要和包的层次一致。
编译后的.class
文件也需要按照包结构存放。如果使用IDE,把编译后的.class
文件放到bin
目录下,那么,编译的文件结构就是:
package_sample
└─ bin
├─ hong
│ └─ Person.class
│ ming
│ └─ Person.class
└─ mr
└─ jun
└─ Arrays.class
编译的命令相对比较复杂,我们需要在src
目录下执行javac
命令:
javac -d ../bin ming/Person.java hong/Person.java mr/jun/Arrays.java
在IDE中,会自动根据包结构编译所有Java源码,所以不必担心使用命令行编译的复杂命令。
唯一包名
为了保证包名的唯一性,要用一个域名以逆序的形式作为包名,然后对于不同的工程使用不同的子包。例如,域名horstmann.com,逆序来写,就得到了包名com.horstman。然后可追加一个工程名,如com.horstmann.corejava。如果再把Employee类放在这个包里,那么这里类的“完全限定”名就是com.horstmann.corejava.Employee;
import
一个类可以使用所属包中所有类,以及其他包中的公共类。
我们可以由三种方式访问另一个包中的公共类。
第一种方式是完全限定名:
var today = java.time.LocalDate.now();
第二种使用import导入一个包中特定类,这样就不用写全名了
import java.time.LocalDate;
……
var today = LocalDate.now();
第三种使用import配合通配符*,导入一个特定的包。
import java.time.*;
需要注意的是,只能使用*导入一个包,而不能使用
import java.*;
或
import java.*.*
导入以java为前缀的所有包。
命名冲突
发生命名冲突情况下,需要注意包了。例如,java.util和java.sql包都有Date类。如果在程序中导入了这两个包:
import java.util.*;
import java.sql.*;
在程序中使用Date类的时候,就会出现一个编译错误。
这个时候,就需要使用完全限定名。
var deadline = new java.util.Date();
var today = new java.sql.Date(...);
静态导入
import语句还可以导入静态方法和静态字段(该方法很少使用),而不只是类。
例如
import static java.lang.System.*;
就可以使用System类的静态方法和静态字段,而不必加类名前缀。
out.print("hello");
包作用域
于同一个包的类,可以访问包作用域的字段和方法。不用public
、protected
、private
修饰的字段和方法就是包作用域。例如,Person
类定义在hello
包下面:
package hello;
public class Person {
// 包作用域:
void hello() {
System.out.println("Hello!");
}
}
Main
类也定义在hello
包下面:
package hello;
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.hello(); // 可以调用,因为Main和Person在同一个包
}
}
注意:使用包作用域是一个非常不好的行为,容易造成一些问题出现
常用包介绍
- java.lang—-包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能
- java.net—-包含执行与网络相关的操作的类和接口。
- java.io —-包含能提供多种输入/输出功能的类。
- java.util—-包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
- java.text—-包含了一些java格式化相关的类
- java.sql—-包含了java进行JDBC数据库编程的相关类/接口
- java.awt—-包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
练习
项目根目录为C:\Users\admin\Desktop\code\java,然后创建以下目录结构:
java
│─ src
│ └─ com
│ └─ studyjava
│ └─ demo
│ └─ Demo1.java
│
└─ bin
在src目录下执行
……\java\src>javac -d ../bin com/studyjava/demo/Demo1.java
此时,会创建bin/studyjava/demo/Demo1.class文件,然后切换到bin目录,执行以下命令
……\java\bin>java com/studyjava/demo/Demo1
hello java