V
Vel·ToolKit
简洁 · 高效 · 即开即用
ZH
第 7 章 / 共 20 章

包、访问控制与 import

package、四种访问修饰符、import、JAR

为什么需要包

包(package)是 Java 的命名空间,作用:避免不同库的同名类冲突、组织代码层级、配合访问修饰符做封装。每个 .java 文件第一行(如果有)必须是 package 声明,后续才是 import 与类。

// src/main/java/com/example/user/User.java
package com.example.user;

public class User {
    public String name;
}

目录与包名约束

包名约定:全小写、点号分层、通常以组织反向域名开头(如 com.example.myapp)。**目录结构必须与包名一致**——package com.example.user 的文件必须放在 com/example/user/ 目录下。

src/main/java/
├── com/example/
│   ├── user/
│   │   ├── User.java        // package com.example.user;
│   │   └── UserService.java // package com.example.user;
│   └── order/
│       └── Order.java        // package com.example.order;
└── Main.java                  // 默认包(不推荐)

import 与 import static

import 把另一个包里的类名引入当前文件作用域,从此可用短名调用。同包内的类不需要 import。java.lang.* 是"默认导入"——String / Math / System 等都不用 import。

// Greeter.java
package com.example.app;

import java.util.List;             // 单类导入(推荐)
import java.util.ArrayList;
import java.util.*;                 // 整包通配(一般不推荐,可读性差)

import static java.lang.Math.PI;    // 静态导入:直接用 PI 而非 Math.PI
import static java.lang.Math.sqrt;

public class Greeter {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>(Arrays.asList("Alice", "Bob"));
        System.out.println(names);
        System.out.println(PI);
        System.out.println(sqrt(2));
    }
}

四种访问修饰符

Java 通过修饰符控制成员的可见性。从严到松依次是 private < 包私有(default)< protected < public。

修饰符        本类  同包  子类  其它包
--------     ----  ----  ----  ------
private       ✓     ✗     ✗     ✗
(不写)       ✓     ✓     ✗     ✗     ← 包私有(默认)
protected     ✓     ✓     ✓     ✗
public        ✓     ✓     ✓     ✓
// Visibility.java
package com.example.app;

public class Visibility {
    public    int pub   = 1;   // 谁都能访问
    protected int prot  = 2;   // 同包 + 子类
              int pkg   = 3;   // 同包(不写修饰符)
    private   int priv  = 4;   // 只在本类

    public static void main(String[] args) {
        Visibility v = new Visibility();
        // 本类内 4 个都能访问
        System.out.println(v.pub + " " + v.prot + " " + v.pkg + " " + v.priv);
    }
}

顶层类与 public class 规则

一个 .java 文件可以包含多个顶层类,但其中**最多只有一个**能是 public,且 public 类的名字必须与文件名完全一致。其它非 public 顶层类只能在本文件内被使用。

// User.java   <-- 文件名必须叫 User.java
package com.example.app;

public class User {            // public 顶层类必须与文件同名
    String name;
}

class Helper {                  // 包私有的辅助类,可以共存
    static String tag = "util";
}

JAR 包:发布与运行

JAR 本质是一个 ZIP 压缩包,里面装着 .class 文件、资源与 META-INF/MANIFEST.MF 描述。jar 命令打包,java -jar 运行。第三方库(Maven 中央仓库下载的)就是一堆 JAR。

# 假设源码已 javac 编译到 build/ 目录
$ jar cfe app.jar com.example.app.Main -C build .
# c = create, f = file 名, e = entry-point 主类

$ java -jar app.jar
Hello, World!

# 查看 jar 内容
$ jar tf app.jar
META-INF/
META-INF/MANIFEST.MF
com/example/app/Main.class
...