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

    • 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)

"李眉把装机文档往群里一扔:'JDK 8安装步骤写好了,Windows的,每一步都截了图。'白歌扫了一眼:'环境变量那块再写细点,JAVA_HOME、Path、CLASSPATH三个都要讲清楚。'小崔在下面回复:'李姐威武!终于不用每次配环境都百度了。'"

JDK安装与配置

本章定位

手把手在Windows上安装JDK 8,深入理解JAVA_HOME、Path、CLASSPATH环境变量的作用和原理,掌握java/javac -version验证安装的正确姿势。这是编程的"装机第一步"。


JDK vs JRE vs JVM 关系深度剖析

包含关系图

职责划分表

组件英文全称一句话职责包含什么谁需要
JDKJava Development Kit开发和运行Java程序JRE + javac + jar + javadoc + javap开发者
JREJava Runtime Environment仅运行Java程序JVM + rt.jar核心类库最终用户
JVMJava Virtual Machine执行字节码类加载器 + JIT编译器 + GC + 执行引擎任何运行Java的地方

三者关系的经典类比

如果把Java程序比作一辆汽车:
    JDK = 汽车制造工厂(包含生产线 + 测试跑道 + 所有工具)
    JRE = 公路系统(包含道路 + 交通规则)
    JVM = 发动机(真正让车跑起来的核心)

JDK 8 下载与安装

下载Oracle JDK 8

版本说明:本教程使用 Oracle JDK 8u202(JDK 8的最后一个免费商用版本)或 OpenJDK 8(完全开源)。两者API完全一致,企业环境中根据授权策略选择。

下载地址:

  • Oracle JDK 8(需注册Oracle账号):https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
  • OpenJDK 8(可选的免费替代):https://adoptium.net/download/

Windows安装步骤

  1. 双击安装包jdk-8u202-windows-x64.exe
  2. 安装目录选择 C:\Program Files\Java\jdk1.8.0_202\(建议保持默认)
  3. 等待安装完成。注意:安装过程中会弹出JRE安装窗口,这是独立JRE(可取消,因为JDK已自带JRE)。
  4. 安装完成后,目录结构如下:
C:\Program Files\Java\jdk1.8.0_202\
├── bin/          ← 可执行文件(javac.exe, java.exe, javap.exe...)
├── jre/          ← JDK自带的JRE
│   ├── bin/
│   └── lib/
│       └── rt.jar   ← 核心类库(运行时)
├── lib/          ← JDK开发工具库
│   └── tools.jar    ← javac等编译器核心代码
├── include/      ← JNI本地调用头文件
└── src.zip       ← JDK核心类库源码(学习JDK源码从这里开始)

环境变量配置:JAVA_HOME、Path、CLASSPATH

环境变量是操作系统级别的全局配置,告诉命令行"javac在哪"、"运行时类库在哪"。这是初学者最容易配错的地方。

配置步骤(Windows 10/11)

步骤一:打开环境变量配置

右键"此电脑" → 属性 → 高级系统设置 → 环境变量。分为用户变量(仅当前用户生效)和系统变量(所有用户生效)。建议配置到系统变量。

步骤二:配置JAVA_HOME

变量名变量值
JAVA_HOMEC:\Program Files\Java\jdk1.8.0_202
说明:JAVA_HOME 指向JDK安装根目录(不是bin目录)。
用途:许多Java工具(Tomcat、Maven、Gradle、Eclipse/IDEA)都依赖JAVA_HOME定位JDK。

步骤三:配置Path

在系统变量Path中新增一条:

%JAVA_HOME%\bin

注意:放在Path的靠前位置,避免被其他程序的java.exe覆盖(如某些软件自带的旧版Java)。

步骤四:配置CLASSPATH(可选)

变量名变量值
CLASSPATH.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar
说明:
.            → 当前目录(重要!不加这个可能找不到当前目录下的.class)
dt.jar       → Java设计时API(Swing等)
tools.jar    → javac等编译工具的核心代码

JDK 8中仍需配置,JDK 9+ 因模块化已不需要tools.jar和dt.jar。
实际上,JDK 8 日常开发中,只要确保 "." 在CLASSPATH中即可,
java命令默认已自动包含rt.jar,无需手动指定。

最佳实践:JDK 8通常不需要手动设置CLASSPATH环境变量。当你使用java -cp或java -classpath参数时,命令行参数会覆盖CLASSPATH环境变量。对初学者而言,不设CLASSPATH比设置错误要好。


验证安装

验证清单

打开新的命令提示符窗口(Win+R → cmd),依次执行以下命令:

命令预期结果验证目的
java -version显示JDK版本信息验证java命令可用
javac -version显示javac版本信息验证javac命令可用
echo %JAVA_HOME%显示JDK安装路径验证JAVA_HOME配置正确
echo %Path%包含JDK/bin路径验证Path配置正确

正确输出示例

C:\Users\xiaocui> java -version
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

C:\Users\xiaocui> javac -version
javac 1.8.0_202

C:\Users\xiaocui> echo %JAVA_HOME%
C:\Program Files\Java\jdk1.8.0_202

代码示例:验证JDK环境配置的Java程序

白歌给小崔写了一个"JDK环境自检"程序,确保团队每个人的开发环境一致:

/**
 * JDKEnvChecker.java
 * 用途:验证JDK 8环境配置是否正确
 * 场景:飞翔科技新人入职,白歌要求新员工运行此程序确认环境就绪
 */
public class JDKEnvChecker {
    public static void main(String[] args) {
        String companyName = "广州飞翔科技";
        String checkerVersion = "v1.0";
        boolean allPassed = true;

        System.out.println("═══════════════════════════════════════════");
        System.out.println("  " + companyName);
        System.out.println("  JDK 8 开发环境自检程序 " + checkerVersion);
        System.out.println("═══════════════════════════════════════════");
        System.out.println();

        // 检查1:Java版本
        String javaVersion = System.getProperty("java.version");
        System.out.print("【检查1】Java 版本                      : ");
        System.out.println(javaVersion);
        if (!javaVersion.startsWith("1.8")) {
            System.out.println("  ⚠ 警告:非JDK 8版本!本教程基于JDK 8。");
            allPassed = false;
        } else {
            System.out.println("  ✓ JDK 8版本正确");
        }

        // 检查2:Java厂商
        String javaVendor = System.getProperty("java.vendor");
        System.out.print("【检查2】Java 厂商                      : ");
        System.out.println(javaVendor);

        // 检查3:JAVA_HOME环境变量
        String javaHome = System.getProperty("java.home");
        System.out.print("【检查3】java.home 系统属性             : ");
        System.out.println(javaHome);

        String envJavaHome = System.getenv("JAVA_HOME");
        System.out.print("【检查4】JAVA_HOME 环境变量             : ");
        if (envJavaHome != null) {
            System.out.println(envJavaHome);
            System.out.println("  ✓ JAVA_HOME 已配置");
        } else {
            System.out.println("(未设置)");
            System.out.println("  ⚠ 建议配置JAVA_HOME,方便Tomcat/Maven等工具使用");
            allPassed = false;
        }

        // 检查4:JVM内存
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
        System.out.print("【检查5】JVM 最大可用内存               : ");
        System.out.println(maxMemory + " MB");

        // 检查5:可用处理器数
        int processors = Runtime.getRuntime().availableProcessors();
        System.out.print("【检查6】可用处理器核心数               : ");
        System.out.println(processors + " 核");

        // 检查6:时区
        String timezone = System.getProperty("user.timezone");
        System.out.print("【检查7】用户时区                       : ");
        System.out.println(timezone != null ? timezone : "(未设置)");

        // 检查7:文件编码
        String fileEncoding = System.getProperty("file.encoding");
        System.out.print("【检查8】默认文件编码                   : ");
        System.out.println(fileEncoding);
        if (!"UTF-8".equalsIgnoreCase(fileEncoding)) {
            System.out.println("  ⚠ 建议在IDEA中设置文件编码为UTF-8,避免中文乱码");
        }

        // 最终结论
        System.out.println();
        System.out.println("═══════════════════════════════════════════");
        if (allPassed) {
            System.out.println("  检查结果:✓ 全部通过!可以开始Java开发了。");
        } else {
            System.out.println("  检查结果:⚠ 存在警告,请根据上述提示处理。");
        }
        System.out.println("  愿你朝华相顾,愿你前程似锦。");
        System.out.println("═══════════════════════════════════════════");
    }
}

运行输出(正确配置的Windows环境):

═══════════════════════════════════════════
  广州飞翔科技
  JDK 8 开发环境自检程序 v1.0
═══════════════════════════════════════════

【检查1】Java 版本                      : 1.8.0_202
  ✓ JDK 8版本正确
【检查2】Java 厂商                      : Oracle Corporation
【检查3】java.home 系统属性             : C:\Program Files\Java\jdk1.8.0_202\jre
【检查4】JAVA_HOME 环境变量             : C:\Program Files\Java\jdk1.8.0_202
  ✓ JAVA_HOME 已配置
【检查5】JVM 最大可用内存               : 1820 MB
【检查6】可用处理器核心数               : 8 核
【检查7】用户时区                       : Asia/Shanghai
【检查8】默认文件编码                   : GBK
  ⚠ 建议在IDEA中设置文件编码为UTF-8,避免中文乱码

═══════════════════════════════════════════
  检查结果:⚠ 存在警告,请根据上述提示处理。
  愿你朝华相顾,愿你前程似锦。
═══════════════════════════════════════════

核心原理:JVM为什么能找到并执行你的.class文件

类加载的查找路径

JVM启动后需要加载Hello.class,它按以下顺序查找:

类加载器负责范围查找路径
Bootstrap ClassLoaderJava核心类库%JAVA_HOME%/jre/lib/rt.jar
Extension ClassLoaderJava扩展库%JAVA_HOME%/jre/lib/ext/
Application ClassLoader用户自定义类CLASSPATH环境变量(默认含.当前目录)

Path vs CLASSPATH 的本质区别

维度PathCLASSPATH
作用对象操作系统JVM
查找什么可执行文件(.exe)Java类文件(.class)和jar包
用途找到javac.exe和java.exe找到编译/运行时依赖的类
默认值操作系统自带路径当前目录.
分隔符分号;(Windows)分号;(Windows)

记忆口诀:"Path找命令,CLASSPATH找类"。


第二个代码示例:使用-cp指定类路径

飞翔科技的项目结构如下,白歌教小崔如何用-cp参数:

C:\Users\xiaocui\feixiang-project\
├── src\
│   └── com\
│       └── feixiang\
│           └── CompanyInfo.java
└── classes\          ← 编译输出目录
package com.feixiang;

/**
 * CompanyInfo.java
 * 路径: src/com/feixiang/CompanyInfo.java
 * 场景:飞翔科技项目中的公司信息类
 */
public class CompanyInfo {
    private String companyName = "广州飞翔科技";
    private int foundedYear = 2018;
    private String domain = "www.feixiang.net";
    private int employeeCount = 12;

    public void printInfo() {
        System.out.println("═══════════════════════════════");
        System.out.println("  公司名称 : " + companyName);
        System.out.println("  成立年份 : " + foundedYear + " 年");
        System.out.println("  官方网站 : " + domain);
        System.out.println("  员工人数 : " + employeeCount + " 人");
        System.out.println("═══════════════════════════════");
    }

    public static void main(String[] args) {
        CompanyInfo info = new CompanyInfo();
        info.printInfo();
        System.out.println("愿你朝华相顾,愿你前程似锦。");
    }
}

编译和运行命令(带包路径):

# 步骤1:进入项目根目录
C:\Users\xiaocui> cd feixiang-project

# 步骤2:编译(-d 指定输出目录到classes)
C:\Users\xiaocui\feixiang-project> javac -d classes src\com\feixiang\CompanyInfo.java

# 步骤3:运行(-cp 指定类路径为classes目录)
C:\Users\xiaocui\feixiang-project> java -cp classes com.feixiang.CompanyInfo
运行输出:
═══════════════════════════════
  公司名称 : 广州飞翔科技
  成立年份 : 2018 年
  官方网站 : www.feixiang.net
  员工人数 : 12 人
═══════════════════════════════
愿你朝华相顾,愿你前程似锦。

注意:运行带package的类时,必须使用完全限定名 com.feixiang.CompanyInfo,且类路径必须指向包的根目录(classes/),而非.class文件所在目录。


易错场景与面试考点

反例一:JAVA_HOME配成了bin目录

# ❌ 错误配置
JAVA_HOME = C:\Program Files\Java\jdk1.8.0_202\bin   # 多了\bin!

# 后果
# 很多依赖JAVA_HOME的工具(如Maven、Tomcat)会拼接 %JAVA_HOME%\bin\java.exe
# 拼接后就变成了 C:\...\jdk1.8.0_202\bin\bin\java.exe → 找不到!

纠正:

# ✅ 正确配置
JAVA_HOME = C:\Program Files\Java\jdk1.8.0_202        # JDK根目录,不含bin

反例二:配置完环境变量后没开新命令行

# ❌ 错误:在同一个命令行窗口验证
C:\Users\xiaocui> set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_202
C:\Users\xiaocui> javac -version
'javac' 不是内部或外部命令...    # 刚配的没生效?

原因:Windows命令提示符在启动时读取环境变量。通过"系统属性"修改后,必须重新打开cmd窗口才能生效。

反例三:Path中已有其他Java路径的冲突

# ❌ 错误:Path中有多个Java路径
C:\Users\xiaocui> where java
C:\Program Files\Java\jdk1.8.0_202\bin\java.exe      ← 想要的
C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe  ← 捣乱的(旧版)

C:\Users\xiaocui> java -version
java version "9.0.4"    # 不是预期的8!

纠正:将%JAVA_HOME%\bin移到Path变量的最前面,或删除其他Java路径。

面试高频题

Q1:JAVA_HOME 和 Path 有什么区别?为什么要配JAVA_HOME?

Path是操作系统级别的环境变量,让命令行能找到javac.exe和java.exe。JAVA_HOME不是操作系统必需的,但它是Java生态的约定标准——Tomcat、Maven、Gradle、Eclipse、IntelliJ IDEA等工具都通过JAVA_HOME来定位JDK安装目录。如果只配Path不配JAVA_HOME,用命令行可以编译运行,但上述工具可能找不到JDK。

Q2:CLASSPATH 环境变量和 java -cp 参数有什么区别?

CLASSPATH环境变量是全局生效的,一旦设置会影响所有Java程序。java -cp(或java -classpath)是命令行级别的,只影响当次运行。推荐使用-cp参数,因为全局CLASSPATH容易被遗忘、导致跨项目类冲突或版本不一致。

Q3:为什么有时候 java Hello 报"NoClassDefFoundError"?

最常见原因:① 类路径不对——运行java Hello时,当前目录下没有Hello.class;② 类名写错——大小写敏感(Hello和hello是不同的);③ 包路径问题——类声明了package com.feixiang;但直接运行java Hello,应该用java com.feixiang.Hello且类路径指向包的根目录;④ CLASSPATH 缺少.——即使配置了CLASSPATH,也必须包含.表示当前目录。

Q4:javac 和 java 命令分别做了什么事?

javac是Java编译器,负责将.java源代码文件编译为.class字节码文件。编译过程包括:词法分析 → 语法分析 → 语义分析 → 生成字节码。java命令启动JVM,加载.class字节码文件并执行其中的main方法。如果指定的是.jar文件,JVM从META-INF/MANIFEST.MF中读取Main-Class入口。


本章小结:JDK包含JRE,JRE包含JVM。JAVA_HOME指向JDK安装根目录,Path确保命令行能找到javac/java命令,CLASSPATH告诉JVM到哪里找.class文件(推荐用-cp代替全局CLASSPATH)。两个核心验证命令:java -version和javac -version。配置完记得重新打开命令行窗口。

上一页
解释型语言与编译型语言对比
下一页
JDK、JRE、JVM 详解