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");

包作用域

于同一个包的类,可以访问包作用域的字段和方法。不用publicprotectedprivate修饰的字段和方法就是包作用域。例如,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