Java package(包)

介绍

从前面的例子中, 我们其实发现了一个问题, 我们运行的示例代码都使用的同一个类名 Yi21Runner , 其实这并不是一种值得提倡的做法, 因为如果每次都使用同一个类名, 那么我们我在运行这段代码的时候, 势必都会修改其实现的主体, 在教程中问题不算大, 但是在实际的项目中, 不同代码负责不同的作用, 然后我们再把他们结合起来实现更多, 更强 的功能.

那么我们换其他的名字呢? 比如 Hello 可以嘛? Wheel 可以嘛? 当然也可以...但是我们还需要了解一点, Java 作为一个开源的编程语言, 有强大的开源开源社区, 很多人都会为这个社区做出一种贡献 --- 贡献自己的代码,  让别人可以使用, 比如我们想造模拟汽车的运行, 现在的汽车是有车轮 (Wheel) 的对吧? 但是可能在社区中已经也有造出了车轮 (Wheel), 这样很多时候我们不用自己再造车轮了, 我们直接拿来用就可以了. 但是用了一下你发现 他那个车轮是自行车车轮, 你没法用, 于是你不得不自己再造个车轮. 这个时候车轮这个名字已经被占用了, 你就无法再使用 Wheel 这个类名了, 当然你仍然可以选择 Wheel2 作为合法的类名, 但是要相信,很多时候不仅仅是你一个人会这样想, 于是有了 WheelX, Wheel2X, WeirdWheel 等等...

Java 中为了避免这样的困境, 提供一种解决方案: package (包)

包的作用

从上面我们可以看出, 首先可以解决类命名冲突的问题, 避免大家为了想使用同一个类名, 而无法实现而最终使用了一个冗长而又奇怪的类名.

除此以外, 包还有以下作用:

  1. 对功能类似的代码进行归集, 便于查找与使用.
  2. 控制外部对包内的访问, 避免部分内部运算遭到外部影响, 而出现不可预期的后果

使用官方包

这里我们使用一个 java 的系统包, 来做一些系统级的操作 - 退出程序, 代码如下:

import java.lang.System;

public class Yi21Runner {
    public static void main(String[] args) {
        System.out.println("Hello");
        System.exit(0);
        System.out.println("No output here");
    }
}

首先我们通过 import 语句, 引入了 java.lang.System 类, 这个是 java 的系统包.

我们就可以使用 System 的方法 exit 了. exit 意味着程序退出, 程序退出后, 后面的语句将不再执行, 因此我们这段代码的执行结果是:

Hello

另外值得注意的是, 如果我们不使用 import 导入  java.lang.System 类, 在代码中完整的使用:

java.lang.System.exit(0);

也是允许的, 但是我们不建议这么做, 因为这样会使得代码看起来非常冗长, 而且很多IDE也支持自动导入类了, 写起来也不会特别麻烦.

创建包

我们已经学会了, 如何去使用一个包, 现在是时候我们去创建一个属于我们自己的包了, 在创建一个包之前, 首先我们要先了解以下的基础知识:

包名的定义

定义包名的语法如下:

package 层次1[.层次2[.层次N(...)]];

包名的命名规则如下:
  1. 要符合 Java 标识符的要求(比如不能以数字开头, 如果忘记了请点击 这里 查看)
  2. 包名全部由小写字母构成
  3. 如果包名包含多个层次, 使用 . (英文句号)分割
  4. 包名的层次一般由大及小, 比如 com.yi21.java
  5. 层次1 不能以 java 命名, 这是Java为自身保留的, 如果定义, 编译时: Java 报 Prohibited package name: java 错误
几个合法, 包名的示例
  • com.yi21.java (这里的 java 不在层次1中, 所以是允许使用的)
  • com.yi21
  • com.google.android

package 通常定义在 Java 源文件的首行, 如果一个 Java 源文件没有指定 package, 那么他会被放进一个默认包(也可以理解为顶层包中), 但是实际开发中, 除了少数示例程序, 我们通常还是会使用 package 的.

包文件的存放路径

通常包文件的存放目录与, 包名的层次保持一致:

比如 Yi21JavaPackage 类, 在包

com.21yi.java

中, 其对应的路径就该是

com/21yi/java/Yi21JavaPackage.java

一个包下面可以放多个类文件.

以下是我们定义的两个包文件:

一. com/21yi/java/Yi21JavaPackage.java :

package com.yi21.java;

public class Yi21JavaPackage {
    public static void hello() {
        System.out.println("I'm Package");
    }
}

Yi21JavaPackage 的 hello 方法输出 I'm Package.

二. com/21yi/java/Yi21JavaCase.java :

package com.yi21.java;

public class Yi21JavaCase {
    public static void hello() {
        System.out.println("I'm Case.");
    }
}

Yi21JavaCase 的 hello 方法输出 I'm Case.

再说包的导入

之前我们通过 import 引用过了一个 java 的系统类 System. 

当然, 我们可以通过一行行的 import:

import com.yi21.java.Yi21JavaCase;
import com.yi21.java.Yi21JavaPackage;

完成对这两个包的引用. 但是 Java 中同样也提供了, 通过 * 通配符完成对同一个包下, 所有类, 接口等的导入, 示例如下:

import com.yi21.java.*;

public class Yi21Runner {
    public static void main(String[] args) {
        Yi21JavaPackage.hello();
        Yi21JavaCase.hello();
    }
}

在这里, 我们通过了 * 完成了对包 com.yi21.java 下所有类的导入, 我们也可以直接使用这些类了, 输出结果如下:

I'm Package
I'm Case.

以上就是 Java Package (包) 的使用了, 在上面中, 我们提到, 包可以限制外部内包内的访问, 那么如可控制呢?

这个时候我们就会需要用到访问修饰符了, 除了访问修饰符外, 还有一些具有其他功能的修饰符需要介绍, 因此, 我们将他们并在了一起, 放到了下一节中, 详情请看 Java 的嵌套类 .