乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Java概述与环境搭建

    • Java概述与环境搭建
    • Java语言概述
    • 解释型语言与编译型语言对比
    • JDK安装与配置
    • JDK、JRE、JVM 详解
    • HelloWorld程序详解
    • IDE 介绍
  • 第2章 标识符与基本数据类型

    • 章节导读
    • 变量概述
    • 常量概述
    • 基本类型与包装类
    • 字节型 byte
    • 短整型 short
    • 整型 int
    • 长整型 long
    • 单精度浮点型 float
    • 双精度浮点型 double
    • 字符型 char
    • 布尔型 boolean
    • 类型转换
  • 第3章 运算符与表达式

    • 章节导读
    • 算术运算符
    • 赋值运算符
    • 关系运算符
    • 逻辑运算符
    • 位运算符
    • 条件运算符
    • 运算符优先级
    • 表达式
  • 第4章 流程控制

    • 章节导读
    • 常见的程序运行流程
    • if-else 选择结构
    • switch 多分支选择
    • while 循环
    • do-while 循环
    • for 循环
    • break 与 continue
  • 第5章 数组

    • 章节导读
    • 一维数组
    • 多维数组
    • Arrays 工具类
  • 第6章 类与对象

    • 章节导读
    • 类与对象
    • 方法定义与调用
    • 构造方法
    • 封装
    • 访问修饰符
    • package 与 import
    • static 关键字
    • this 关键字
    • 参数传递 详解
    • 枚举
    • 成员内部类
    • 局部内部类
    • 静态内部类
    • 匿名内部类
  • 第7章 接口与继承

    • 章节导读
    • 继承
    • super 关键字
    • final 关键字
    • 多态
    • 向上转型与向下转型
    • 抽象类
    • 接口
    • 抽象类与接口对比
  • 第8章 注解

    • 章节导读
    • 注解基础
    • 元注解详解
    • 自定义注解
  • 第9章 常用类

    • 章节导读:Java 常用类
    • Object 类:万类之祖
    • 包装类:基本类型的对象化
    • String:不可变的字符串
    • StringBuffer:线程安全的可变字符串
    • StringBuilder:可变的字符串构建器
    • Math:数学运算工具类
    • Random:伪随机数生成器
    • 大数值运算 详解
    • 日期时间API 详解
  • 第10章 异常机制

    • 章节导读
    • 异常体系与分类
    • try-catch-finally
    • try-with-resources
    • throws 与 throw
    • 自定义异常
  • 第11章 泛型

    • 章节导读
    • 泛型基础
    • 通配符与PECS原则
    • 类型擦除
  • 第12章 集合框架

    • 章节导读
    • 集合框架概述
    • ArrayList
    • LinkedList
    • HashMap 详解
    • LinkedHashMap 详解
    • TreeMap 详解
    • HashSet
    • TreeSet 详解
    • TreeSet 与 Comparable
    • Collections 工具类详解
  • 第13章 IO流

    • 章节导读
    • IO流概述
    • 字节流
    • 字符流
    • 缓冲流
    • 转换流 详解
    • 序列化 详解
    • NIO与Files 详解
    • NIO与Files工具类
  • 第14章 多线程与并发

    • 第十六章 多线程与并发 —— 章节导读
    • 线程基础详解
    • synchronized 详解
    • Lock 与显式锁详解
    • volatile 详解
    • wait 与 notify 详解
    • ThreadLocal详解
    • 原子类详解
    • 并发工具类详解
    • 线程池详解
  • 第15章 反射

    • 章节导读
    • 反射概述与 Class 对象
    • Constructor 与对象创建
    • Field与Method详解
    • 反射应用详解
  • 第16章 JDK8新特性

    • 章节导读
    • Lambda 表达式
    • Stream API 基础
    • Stream API 高级详解
    • Optional 详解
    • 新日期时间API详解
  • 第17章 JDK9-11新特性

    • 章节导读
    • 模块化系统 — Project Jigsaw(JDK 9)
    • var 局部变量类型推断(JDK 10)
    • 集合工厂方法与增强(JDK 9 / 10 / 11)
    • 接口增强:private 方法(JDK 9)
    • Stream API 增强(JDK 9)
    • Optional 增强(JDK 9 / 10 / 11)
    • String 新增方法(JDK 11)
    • HTTP Client 与 Files 增强(JDK 11)
    • 直接运行 Java 源文件 — JEP 330(JDK 11)
  • 第18章 JDK12-17新特性

    • 章节导读
    • Switch 表达式(JDK 12 预览 / JDK 14 正式)
    • 文本块 Text Blocks(JDK 13 预览 / JDK 15 正式)
    • Records 记录类(JDK 14 预览 / JDK 16 正式)
    • 密封类 Sealed Classes(JDK 15 预览 / JDK 17 正式)
    • instanceof 模式匹配(JDK 14 预览 / JDK 16 正式)
    • Switch 模式匹配 — Pattern Matching for switch(JDK 17 预览 / JDK 21 正式)
    • Helpful NPE 与 String 增强(JDK 12 / JDK 14 / JDK 15)
    • Stream 增强(JDK 12 / JDK 16)
    • 日期时间增强 — Day Period 支持(JDK 16)
  • 第19章 JDK18-21新特性

    • 章节导读
    • 虚拟线程(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 序列集合(JDK 21 正式)
    • Switch 模式匹配(JDK 17 预览 / JDK 18 第二预览 / JDK 20 第四预览 / JDK 21 正式)
    • Record 模式匹配(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 未命名模式与变量(JDK 21 预览 / JDK 22 正式)
  • 第20章 JDK 22-25 新特性

    • 章节导读
    • 字符串模板(JDK 22 预览 / JDK 23 第二预览 / JDK 24 第三预览)
    • Stream Gatherers(JDK 22 预览 / JDK 24 第二预览)
    • 隐式声明类与实例方法(JDK 23 预览 / JDK 24 第二预览)
    • 原始类型模式匹配(JDK 24 预览)
  • 附录

    • Java 核心知识点
    • Java SE 专业术语
    • Java特性索引(JDK 8 → 25)

package 与 import

引语:项目越做越大,小崔的代码目录堆了几十个 .java 文件,类名冲突频频发生——他写了三个叫 Utils 的类,编译器都不知道该用哪个。前端开发黄俪建议按功能分包,白歌说:"不仅要把类放进包,还要用好 import——Java 的包机制就是代码的'邮政编码'。"


package:命名空间与物理组织

什么是 package

package 是 Java 的命名空间机制,用于将相关的类和接口组织在一起,同时避免命名冲突。它同时解决了两个问题:

  1. 逻辑层面:提供了类名的命名空间,com.feixiang.hr.Employee 和 com.feixiang.tech.Employee 是两个不同的类
  2. 物理层面:规定了 .java 和 .class 文件在磁盘上的目录结构

package 声明规则

规则说明示例
必须首行package 语句必须是 Java 源文件的第一条非注释语句package com.feixiang.hr;
只能一条每个源文件只能有一条 package 语句——
对应目录包名必须与目录结构一致com.feixiang.hr → com/feixiang/hr/
命名规范全部小写,用 . 分隔层级com.feixiang.hr.util
域名倒置建议使用公司域名的倒置作为根包名com.feixiang 来自 feixiang.com

飞翔科技包结构

飞翔科技项目源码目录结构:

src/
└── com/
    └── feixiang/
        ├── hr/              ← 人力资源模块
        │   ├── Employee.java
        │   ├── HRService.java
        │   ├── InternalAuditor.java
        │   └── util/
        │       └── SalaryHelper.java
        ├── tech/            ← 技术部模块
        │   ├── TechManager.java
        │   └── Department.java
        ├── finance/         ← 财务模块
        │   └── FinanceReport.java
        └── common/          ← 公共模块
            └── CompanyConstant.java

对应的 package 声明:

// com/feixiang/hr/Employee.java
package com.feixiang.hr;

// com/feixiang/hr/util/SalaryHelper.java
package com.feixiang.hr.util;

// com/feixiang/common/CompanyConstant.java
package com.feixiang.common;

import:引入外部类

为什么需要 import

如果不使用 import,每次使用其他包的类都必须写全限定类名(Fully Qualified Name):

// ❌ 没有 import,代码非常冗长
public class App {
    public static void main(String[] args) {
        com.feixiang.hr.Employee emp = new com.feixiang.hr.Employee();
        com.feixiang.hr.HRService service = new com.feixiang.hr.HRService();
        java.util.List<com.feixiang.hr.Employee> list = new java.util.ArrayList<>();
    }
}

使用 import 后:

// ✅ 有 import,代码简洁清晰
import com.feixiang.hr.Employee;
import com.feixiang.hr.HRService;
import java.util.List;
import java.util.ArrayList;

public class App {
    public static void main(String[] args) {
        Employee emp = new Employee();
        HRService service = new HRService();
        List<Employee> list = new ArrayList<>();
    }
}

import 的三种形式

形式语法说明示例
单类导入import 包名.类名;明确导入一个类import com.feixiang.hr.Employee;
通配符导入import 包名.*;导入该包下所有类(不含子包)import java.util.*;
静态导入import static 包名.类名.成员;导入静态成员,可直接使用import static java.lang.Math.PI;

通配符导入的注意事项

// 通配符只导入当前包下的类,不包括子包
import com.feixiang.hr.*;
// ✅ 导入了 com.feixiang.hr.Employee
// ✅ 导入了 com.feixiang.hr.HRService
// ❌ 没有导入 com.feixiang.hr.util.SalaryHelper(子包不会自动导入)

import com.feixiang.hr.util.*;  // 需要单独导入子包

最佳实践:尽量使用单类导入而非通配符。单类导入让依赖关系一目了然,避免了不同包中有同名类时的歧义。大多数 IDE(IntelliJ IDEA、Eclipse)默认使用单类导入。


静态导入(static import)

定义

静态导入(JDK 1.5 引入)允许直接使用类的静态成员(静态字段和静态方法),无需写类名前缀。

语法对比

方式语法使用时的写法
常规导入import com.feixiang.common.CompanyConstant;CompanyConstant.COMPANY_NAME
静态导入字段import static com.feixiang.common.CompanyConstant.*;COMPANY_NAME(直接使用)
静态导入方法import static java.lang.Math.*;sqrt(16) 而非 Math.sqrt(16)

完整示例:飞翔科技常量与工具类

package com.feixiang.hr;

// 静态导入:直接使用常量和静态方法
import static com.feixiang.common.CompanyConstant.COMPANY_NAME;
import static com.feixiang.common.CompanyConstant.MAX_EMPLOYEES;
import static java.lang.Math.round;

/**
 * HR 管理类 —— 展示静态导入的用法
 */
public class HRDashboard {

    public void printDashboard(int currentEmployees) {
        // ✅ 静态导入后可直接使用常量名
        System.out.println("===== " + COMPANY_NAME + " HR 仪表盘 =====");

        // ✅ 直接使用静态方法
        double ratio = (double) currentEmployees / MAX_EMPLOYEES * 100;
        System.out.println("在职人数:" + currentEmployees + " / " + MAX_EMPLOYEES);
        System.out.println("满编率:" + round(ratio) + "%");

        if (currentEmployees >= MAX_EMPLOYEES) {
            System.out.println("【警告】编制已满,暂停招聘!");
        }
    }
}

测试代码:

package com.feixiang;

import com.feixiang.hr.HRDashboard;

public class DashboardTest {
    public static void main(String[] args) {
        HRDashboard dashboard = new HRDashboard();
        dashboard.printDashboard(4500);  // 接近 5000 上限
    }
}

运行输出:

===== 飞翔科技 HR 仪表盘 =====
在职人数:4500 / 5000
满编率:90%

静态导入的陷阱

// ❌ 过度使用静态导入,代码可读性极差
import static java.lang.Math.*;
import static java.lang.System.*;
import static java.util.Arrays.*;

public class Messy {
    public static void main(String[] args) {
        out.println(sqrt(25));   // sqrt 是哪来的?out 是哪来的?
        out.println(abs(-42));   // 看代码的人一头雾水
    }
}

纠正:静态导入只用于高频使用的常量和明确的工具方法。当有歧义时,退回使用类名前缀。

// ✅ 合理使用
import static com.feixiang.common.CompanyConstant.COMPANY_NAME;
import static java.lang.Math.PI;  // PI 语义明确,不会产生歧义

public class Clean {
    public static void main(String[] args) {
        System.out.println(COMPANY_NAME);  // 公司名:语义清晰
        System.out.println(Math.sqrt(25));  // Math.sqrt 保留前缀,可读性更好
    }
}

java.lang 包的自动导入

java.lang 包是 Java 的核心语言包,编译器会自动导入,无需手动写 import。

以下常用类都属于 java.lang 包,可以直接使用:

类别常用类
基本类型包装Integer、Long、Double、Boolean、Character
字符串String、StringBuilder、StringBuffer
系统相关System、Runtime
数学运算Math、StrictMath
异常与错误Exception、Error、Throwable、RuntimeException
反射Class
线程Thread、Runnable
// ✅ 无需 import,直接使用
public class AutoImportDemo {
    public static void main(String[] args) {
        String msg = "Hello 飞翔科技";         // java.lang.String
        System.out.println(msg);               // java.lang.System
        int num = Integer.parseInt("100");     // java.lang.Integer
        Thread current = Thread.currentThread(); // java.lang.Thread
    }
}

不同包同名类的处理

当两个不同的包中有同名类时,不能同时使用通配符导入,必须至少有一个使用全限定类名。

// ====== com/feixiang/hr/DateUtils.java ======
package com.feixiang.hr;

public class DateUtils {
    public static String formatHireDate() {
        return "入职日期格式化(HR版本)";
    }
}

// ====== com/feixiang/tech/DateUtils.java ======
package com.feixiang.tech;

public class DateUtils {
    public static String formatProjectDate() {
        return "项目日期格式化(技术版本)";
    }
}

处理方案

// ❌ 编译错误:对 DateUtils 的引用不明确
import com.feixiang.hr.*;
import com.feixiang.tech.*;

public class App {
    public static void main(String[] args) {
        // DateUtils.formatHireDate();  // 报错!不知道用哪个 DateUtils
    }
}

方案一:导入一个,另一个用全限定类名

// ✅ 明确指定
import com.feixiang.hr.DateUtils;

public class App {
    public static void main(String[] args) {
        System.out.println(DateUtils.formatHireDate());  // 使用导入的
        System.out.println(com.feixiang.tech.DateUtils.formatProjectDate());  // 全限定名
    }
}

方案二:两个都用全限定类名

// ✅ 避免歧义,代码意图最明确
public class App {
    public static void main(String[] args) {
        System.out.println(com.feixiang.hr.DateUtils.formatHireDate());
        System.out.println(com.feixiang.tech.DateUtils.formatProjectDate());
    }
}

完整示例:飞翔科技多模块协作

场景

小崔需要在 HR 模块的代码中使用技术部和公共模块的类。本示例展示 package 声明、import 导入、静态导入的综合应用。

代码

// ====== com/feixiang/common/CompanyConstant.java ======
package com.feixiang.common;

public class CompanyConstant {
    public static final String COMPANY_NAME = "飞翔科技";
    public static final String HR_EMAIL = "hr@feixiang.com";
    public static final int STANDARD_WORK_HOURS = 8;
}

// ====== com/feixiang/tech/Department.java ======
package com.feixiang.tech;

public class Department {
    private String deptName;

    public Department(String deptName) {
        this.deptName = deptName;
    }

    public String getDeptName() {
        return deptName;
    }
}

// ====== com/feixiang/hr/Employee.java ======
package com.feixiang.hr;

public class Employee {
    private String name;
    private double salary;

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() { return name; }
    public double getSalary() { return salary; }
}

// ====== com/feixiang/hr/HRService.java ======
package com.feixiang.hr;

// 常规导入
import com.feixiang.tech.Department;           // 导入技术部类
import java.util.Date;                         // 导入 JDK 类

// 静态导入
import static com.feixiang.common.CompanyConstant.COMPANY_NAME;
import static com.feixiang.common.CompanyConstant.HR_EMAIL;

/**
 * HR 服务类 —— 综合展示 import 的各种用法
 */
public class HRService {

    // java.lang 包自动导入,无需 import
    private String serviceName;

    public HRService(String serviceName) {
        this.serviceName = serviceName;
    }

    /**
     * 处理员工入职
     */
    public void onboardEmployee(Employee emp, Department dept) {
        System.out.println("===== " + COMPANY_NAME + " 入职通知 =====");  // 静态导入的常量
        System.out.println("HR 服务:" + serviceName);
        System.out.println("新员工:" + emp.getName());
        System.out.println("部门:" + dept.getDeptName());  // 来自 com.feixiang.tech
        System.out.println("入职日期:" + new Date());       // java.util.Date
        System.out.println("如有疑问请邮件:" + HR_EMAIL);     // 静态导入的常量

        // java.lang.String 自动导入
        String message = "欢迎 " + emp.getName() + " 加入 " + COMPANY_NAME + "!";
        System.out.println(message);
    }
}

测试代码

// ====== com/feixiang/Main.java ======
package com.feixiang;

import com.feixiang.hr.Employee;
import com.feixiang.hr.HRService;
import com.feixiang.tech.Department;

public class Main {
    public static void main(String[] args) {
        // 创建各模块对象
        Employee emp = new Employee("小崔", 28000.00);
        Department techDept = new Department("技术部-后端组");
        HRService hr = new HRService("飞翔科技HR系统 v1.0");

        // 执行入职流程
        hr.onboardEmployee(emp, techDept);
    }
}

运行输出

===== 飞翔科技 入职通知 =====
HR 服务:飞翔科技HR系统 v1.0
新员工:小崔
部门:技术部-后端组
入职日期:Sun Dec 21 10:00:00 CST 2025
如有疑问请邮件:hr@feixiang.com
欢迎 小崔 加入 飞翔科技!

import 编译原理简述

编译器查找类的优先级:

  1. 当前类所在的包
  2. 单类导入(import com.feixiang.hr.Employee;)
  3. 通配符导入(import com.feixiang.hr.*;)
  4. java.lang 包(自动导入)

易错场景

反例一:package 语句不在首行

// ❌ 编译错误!package 必须在首行
import java.util.Date;
package com.feixiang.hr;  // 错误:package 必须是第一条语句

public class Employee {
}

纠正:

// ✅ package 第一行,import 紧随其后
package com.feixiang.hr;

import java.util.Date;

public class Employee {
}

反例二:混淆通配符导入与子包

// ❌ 错误认知:import com.feixiang.* 会导入 com.feixiang.hr.Employee
import com.feixiang.*;

public class App {
    public static void main(String[] args) {
        // ❌ 编译错误:找不到符号
        // Employee emp = new Employee();
    }
}

纠正:通配符只导入当前包下的类,不递归导入子包。

// ✅ 导入具体包
import com.feixiang.hr.Employee;

public class App {
    public static void main(String[] args) {
        Employee emp = new Employee("白歌", 35000);
    }
}

反例三:静态导入导致可读性灾难

// ❌ 静态导入所有 Math 成员,不清楚 PI 从哪里来
import static java.lang.Math.*;

public class Circle {
    public double area(double r) {
        return PI * r * r;  // PI 从哪来的?必须翻到文件顶部才知道
    }
}

纠正:

// ✅ 保留类名前缀或精确静态导入
import static java.lang.Math.PI;  // 精确导入,语义明确

public class Circle {
    public double area(double r) {
        return PI * r * r;  // 文件顶部就能看到 PI 的来源
    }
}

面试考点

Q1:package 语句有什么规则?

① package 语句必须是 Java 源文件的第一条非注释语句;② 每个源文件只能有一句 package 声明;③ 包名必须与目录结构一致(com.feixiang.hr 对应 com/feixiang/hr/);④ 包名全部小写,采用域名倒置的命名规范;⑤ 如果没有 package 声明,类属于无名包(default package),不推荐在实际项目中使用。

Q2:import java.util.* 会导入 java.util 子包中的类吗?

不会。通配符 * 只匹配当前包下的直接类,不会递归导入子包。例如 import java.util.* 不会导入 java.util.regex.Pattern,需要单独写 import java.util.regex.* 或 import java.util.regex.Pattern。

Q3:import static 和普通 import 有什么区别?

普通 import 导入的是类,使用时仍需写 类名.静态成员;import static 导入的是类的静态成员(字段或方法),使用时可以省略类名前缀。例如 import static java.lang.Math.PI 后可以直接写 PI。静态导入适合高频使用的常量,但过度使用会降低可读性。

Q4:如果两个包中都有同名的 DateUtils 类,如何处理?

① 只导入其中一个,另一个使用全限定类名;② 两个都用全限定类名。不能同时使用通配符导入两个包,编译器会报"引用不明确"错误。

Q5:java.lang 包为什么不需要 import?

java.lang 是 Java 的核心语言包,包含了 Java 语言最基础的类(String、System、Math、Thread 等)。编译器会隐式地为每个源文件添加 import java.lang.*,因此无需手动导入。这是 Java 语言规范的硬性规定(JLS 7.3)。

上一页
访问修饰符
下一页
static 关键字