深入解析JVM、JRE与JDK:Java技术体系的核心基石

在Java技术生态中,JVM、JRE与JDK是三个贯穿开发、运行全流程的核心概念,它们既相互关联、层层嵌套,又各自承担着独特的职责。对于Java开发者而言,深刻理解这三者的定义、功能、架构及内在联系,是掌握Java底层原理、优化程序性能、排查运行故障的基础;对于入门者来说,厘清三者的区别与联系,能快速搭建起Java技术的知识框架,避免陷入概念混淆的误区。本文将从基础定义出发,逐步深入剖析三者的核心架构、工作机制、实战应用及版本迭代,全方位解读它们在Java技术体系中的核心价值,总字数将达到5000字左右,兼顾理论深度与实战指导性。

第一章 开篇:Java技术体系的核心三要素

Java自1995年诞生以来,凭借"一次编写,到处运行"的跨平台特性、面向对象的设计思想以及稳定高效的运行表现,成为全球最流行的编程语言之一,广泛应用于Web开发、移动开发、大数据、云计算、嵌入式系统等多个领域。支撑Java这一强大生态的核心,正是JVM(Java Virtual Machine,Java虚拟机)、JRE(Java Runtime Environment,Java运行时环境)与JDK(Java Development Kit,Java开发工具包)三者的协同工作。

很多初学者在入门Java时,常常会混淆这三个概念:有人认为安装了JDK就等同于拥有了JVM,有人误以为JRE包含JDK,还有人不清楚三者在程序开发与运行中的具体作用。事实上,三者呈现出清晰的"包含与被包含"关系,同时各自承担着不同的角色:JDK包含JRE,JRE包含JVM,三者层层递进、各司其职,共同构成了Java程序从开发到运行的完整链路。

简单来说,JDK是Java开发的"工具箱",提供了所有开发、编译、调试Java程序所需的工具和环境;JRE是Java程序的"运行舞台",提供了程序运行所需的基础环境和核心依赖;JVM是Java跨平台的"核心引擎",负责将Java代码转换为机器可执行的指令,屏蔽底层操作系统的差异。三者的协同工作流程可概括为:开发者使用JDK中的工具编写、编译Java源码,生成字节码文件;JRE提供运行环境,通过JVM加载并执行字节码文件,最终将其转换为对应操作系统的机器指令,实现程序的运行。

本章将先明确三者的基础定义与核心定位,搭建起整体认知框架,为后续的深入解析奠定基础。

1.1 核心定义与定位

1.1.1 JVM(Java Virtual Machine):Java跨平台的灵魂

JVM即Java虚拟机,是一个虚构的计算机,通过软件模拟出一套完整的计算机运行环境,包括处理器、内存、寄存器、指令集等,专门用于执行Java字节码文件。它的核心价值在于"屏蔽底层操作系统和硬件的差异",使得Java程序无需针对不同的操作系统进行修改,只需编译一次生成字节码,就能在安装了对应JVM的任意平台上运行,这也是Java"一次编写,到处运行"(Write Once, Run Anywhere)特性的核心实现。

需要注意的是,JVM本身并不直接执行Java源码,而是执行Java源码编译后生成的字节码(.class文件)。字节码是一种中间代码,介于Java源码和机器指令之间,既保留了Java的面向对象特性,又具备平台无关性。JVM的核心任务就是将这种平台无关的字节码,翻译为当前操作系统可识别的机器指令,进而驱动硬件执行。

此外,JVM还承担着内存管理、垃圾回收、线程调度、安全校验等重要职责,是Java程序稳定、高效运行的关键保障。不同的操作系统(如Windows、Linux、Mac OS)有对应的JVM实现(如Oracle HotSpot、IBM OpenJ9、GraalVM等),但所有JVM都遵循统一的《Java虚拟机规范》,确保同一份字节码在不同平台上的执行结果一致。

1.1.2 JRE(Java Runtime Environment):Java程序的运行基石

JRE即Java运行时环境,是支撑Java程序运行的最小环境集合,它包含了JVM以及Java程序运行所需的核心类库、运行时辅助工具等。简单来说,只要安装了JRE,就可以运行已编译好的Java程序(如.jar文件、.class文件),但无法进行Java程序的开发、编译和调试。

JRE的核心组成部分包括两部分:一是JVM实例,负责字节码的加载、执行和内存管理;二是Java核心类库(如java.lang、java.util、java.io等),这些类库提供了Java程序运行所需的基础功能,比如字符串处理、集合操作、IO操作、网络通信等,开发者无需重复编写这些基础功能,直接调用类库中的方法即可。

对于普通用户而言,若仅需运行Java应用程序(如桌面应用、Web应用客户端),无需安装完整的JDK,只需安装JRE即可,这样可以节省磁盘空间,简化安装流程。但从JDK 9开始,Oracle重构了Java模块化系统(JPMS),不再单独提供独立的JRE安装包,需通过JDK精简或专用运行时镜像工具(jlink)生成,适配不同场景的运行需求。

1.1.3 JDK(Java Development Kit):Java开发的全能工具箱

JDK即Java开发工具包,是Java开发人员必备的工具集合,它包含了完整的JRE,以及用于Java程序开发、编译、调试、打包、文档生成的一系列工具。简单来说,JDK = JRE + 开发工具集,开发者通过JDK提供的工具,完成Java程序从编写到运行的全流程开发工作。

JDK中的开发工具种类繁多,核心工具包括javac(Java编译器,用于将.java源码编译为.class字节码)、java(Java运行工具,用于启动JVM执行字节码)、javadoc(文档生成工具,用于生成Java程序的API文档)、jdb(调试工具,用于排查程序运行中的错误)、javap(反编译工具,用于查看字节码内容,辅助排查底层问题)、jar(打包工具,用于将多个.class文件打包为.jar文件,方便程序部署和分发)等。

此外,JDK还包含了Java核心类库的源码和文档,开发者可以查看源码,深入理解Java类库的实现原理,也可以通过文档快速了解类和方法的使用方式。对于Java开发者而言,安装JDK是开展开发工作的前提,它提供了开发、编译、运行、调试的一站式支持。

1.2 三者的核心关系(图文梳理)

通过前面的定义解析,我们可以明确三者的包含关系:JDK包含JRE,JRE包含JVM,用层级结构表示如下:

JDK(Java开发工具包)

├─ JRE(Java运行时环境)

│ ├─ JVM(Java虚拟机)

│ └─ Java核心类库 + 运行时辅助工具

└─ 开发工具集(javac、java、javadoc、jdb等)

为了更清晰地理解三者的区别与联系,我们通过表格对比三者的核心维度:

维度 JDK (Java Development Kit) JRE (Java Runtime Environment) JVM (Java Virtual Machine)
中文全称 Java 开发工具包 Java 运行时环境 Java 虚拟机
核心作用 开发 + 编译 + 运行 Java 程序 仅运行已编译好的 Java 程序 执行 Java 字节码(.class 文件)
是否包含 JVM 是(通过JRE间接包含) 本身就是 JVM
是否包含开发工具 是(javac、jdb、javadoc等)
是否包含类库 是(完整核心类库) 是(核心类库) 否(依赖JRE提供)
平台依赖性 与操作系统相关(不同OS有对应版本) 与操作系统相关 与操作系统相关,但字节码平台无关
安装大小 最大(包含JRE和开发工具) 中等(仅包含JVM和类库) 最小(JRE的核心部分)
适用人群 Java 开发者、运维人员 普通用户(仅运行Java程序) JVM实现者、底层技术研究者
典型目录 bin(含javac)、lib、jre、include等 bin(只有java)、lib JVM具体实现(如HotSpot的jre/bin)

一句话总结三者的应用场景:想开发Java程序,必须安装JDK;只想运行Java程序,安装JRE即可;而Java程序能跨平台运行,核心依赖JVM的字节码执行能力。

第二章 深度解析JVM:Java跨平台的核心引擎

JVM作为Java技术体系的灵魂,是实现"一次编写,到处运行"的核心载体,其内部架构复杂、功能强大,承担着字节码加载、执行、内存管理、垃圾回收等关键职责。本章将从JVM的核心架构、运行机制、内存模型、垃圾回收、常见实现版本等方面,深入解析JVM的底层原理,帮助读者理解JVM如何工作,以及它在Java程序运行中的核心作用。

2.1 JVM的核心架构

JVM的架构遵循《Java虚拟机规范》,不同实现版本(如HotSpot、OpenJ9)的架构细节略有差异,但核心组件一致,主要包括四大核心模块:类加载子系统、运行时数据区、执行引擎、本地方法接口,四大模块协同工作,完成字节码的加载、执行和管理。

2.1.1 类加载子系统(Class Loading Subsystem)

类加载子系统的核心职责是将磁盘、网络中的.class字节码文件加载到JVM中,并完成验证、准备、解析、初始化四个步骤,最终生成可被JVM使用的Class对象,存入运行时数据区的方法区。类加载的整个流程严格遵循"加载→验证→准备→解析→初始化"的顺序,其中解析步骤可在初始化之后执行(动态绑定场景)。

1. 加载(Loading)

加载是类加载的第一步,核心任务是根据类的全限定名(如java.lang.String),读取.class文件的二进制数据,在方法区中生成对应的Class对象(堆中也会生成该Class对象的引用)。加载的来源可以是本地磁盘(如JDK核心类库的.class文件)、网络(如Web应用中通过网络加载的类)、内存(如动态生成的.class文件)等。

加载阶段由类加载器完成,JVM提供了三层类加载器,采用"双亲委派模型"进行类加载,核心原则是"先让父类加载器尝试加载,父类加载器无法加载时,再由子类加载器自己加载"。三层类加载器分别是:

  • 启动类加载器(Bootstrap ClassLoader):最顶层的类加载器,由C++编写,负责加载JDK核心类库(如rt.jar中的类),不继承ClassLoader类,无法被Java程序直接访问。

  • 扩展类加载器(Extension ClassLoader):负责加载JDK扩展目录(如jre/lib/ext目录)下的类,继承自ClassLoader类,可被Java程序访问。

  • 应用程序类加载器(Application ClassLoader):也称为系统类加载器,负责加载用户编写的Java类(如项目中的.class文件),是默认的类加载器,继承自ClassLoader类,可通过ClassLoader.getSystemClassLoader()获取。

双亲委派模型的核心作用有两个:一是避免类的重复加载(同一个类不会被不同类加载器多次加载);二是保障核心类的安全(如java.lang.String不会被自定义类加载器篡改,防止恶意代码替换核心类)。

2. 验证(Verification)

验证是JVM的"安全关卡",核心任务是检查.class文件的合法性,防止非法字节码破坏JVM运行环境。验证的内容包括:

  • 格式验证:检查.class文件的二进制格式是否符合Java字节码规范,如文件头是否为0xCAFEBABE(Java字节码的标识)、版本号是否兼容等。

  • 语义验证:检查类的结构是否合法,如是否有父类(除Object类外)、方法的参数和返回值类型是否匹配、是否存在非法访问(如访问私有成员)等。

  • 字节码验证:检查字节码指令的合法性,如指令是否符合JVM指令集规范、是否存在无限循环、非法跳转等,确保字节码执行不会破坏JVM内存。

  • 符号引用验证:检查字节码中的符号引用(如类名、方法名、变量名)是否能找到对应的实际引用,避免运行时出现ClassNotFoundException、NoSuchMethodException等异常。

验证阶段若发现非法字节码,会直接抛出VerifyError异常,终止类加载流程,从而保障JVM的运行安全。

3. 准备(Preparation)

准备阶段的核心任务是为类的静态变量分配内存(存储在方法区),并设置默认初始值(而非代码中赋予的最终值)。需要注意的是,此时不执行任何Java代码,仅完成静态变量的内存分配和默认初始化。

例如:public static int a = 10; 在准备阶段,a的值会被设置为int类型的默认值0,而非10;10的赋值操作会在初始化阶段完成。对于final修饰的静态变量(常量),在准备阶段会直接赋予代码中指定的初始值,例如public static final int b = 20; 在准备阶段,b的值会被设置为20。

4. 解析(Resolution)

解析阶段的核心任务是将字节码中的符号引用转换为直接引用(如内存地址、指针),为后续方法调用提供准确的内存地址。符号引用是字符串形式的逻辑引用(如"java.lang.String"),直接引用是可以直接定位到目标的物理引用(如内存地址)。

解析的对象包括类、接口、方法、字段等,例如将"java.lang.String"这个符号引用,解析为其对应的Class对象在方法区中的内存地址。解析阶段可以在初始化阶段之前执行,也可以在初始化阶段之后执行(动态绑定场景,如多态调用)。

5. 初始化(Initialization)

初始化是类加载流程的最后一步,也是唯一会执行Java代码的阶段,核心任务是执行类的静态代码块和静态变量的显式赋值操作,完成类的初始化。初始化遵循"主动使用才会触发"的原则,主动使用的场景包括:

  • 创建类的实例(new关键字);

  • 调用类的静态方法;

  • 访问类的静态变量(除final常量外);

  • 反射调用类(如Class.forName());

  • 初始化子类时,父类会先被初始化。

被动使用(如访问父类的静态变量、通过数组引用类)不会触发类的初始化。初始化阶段会按照静态代码块和静态变量的定义顺序执行,例如:

public class Test {

public static int a = 10;

static {

a = 20;

}

}

初始化阶段会先执行a = 10,再执行静态代码块中的a = 20,最终a的值为20。

2.1.2 运行时数据区(Runtime Data Area)

运行时数据区是JVM用于存储程序运行过程中所有数据的区域,是JVM内存管理的核心,也是面试和性能调优的重点。根据《Java虚拟机规范》,运行时数据区分为线程共享区和线程私有区,前者被所有线程共享,会存在内存溢出(OOM)风险且涉及垃圾回收;后者与线程一一对应,线程隔离,风险更低。

1. 线程共享区

线程共享区包括堆(Heap)和方法区(Method Area),是JVM内存管理的核心区域。

(1)堆(Heap):堆是JVM中最大的内存区域,也是垃圾回收的核心区域,负责存储所有对象实例和数组(几乎所有new出来的对象都在这里)。堆的大小可通过JVM参数配置(如-Xms、-Xmx),默认情况下会随着程序的运行动态调整。

JDK8及以后,堆分为"新生代"和"老年代",新生代又分为"Eden区"和两个"Survivor区(From/To)",默认比例为8:1:1。新创建的对象优先存入Eden区,当Eden区满时,会触发Minor GC(轻量垃圾回收),存活对象进入Survivor区;多次GC后仍存活的对象,会被晋升到老年代;老年代满时,会触发Full GC(全量垃圾回收),耗时较长,会影响程序的运行性能。

堆是内存溢出的高发区域,当堆内存不足,无法分配新对象时,会抛出OutOfMemoryError(OOM)异常。

(2)方法区(Method Area):方法区用于存储类的元数据(类结构、字段、方法、构造方法)、常量池(final常量、字符串常量)、静态变量、编译后的字节码等。方法区的大小也可通过JVM参数配置,不同JVM实现的实现方式不同:

  • JDK7及之前,方法区被称为"永久代",使用JVM内存,可通过-XX:PermSize、-XX:MaxPermSize参数配置大小;

  • JDK8及以后,永久代被移除,替换为"元空间(Metaspace)",使用本地内存(操作系统内存),默认情况下不易出现OOM,但配置不当(如元空间大小限制过严)仍会触发OOM异常。

方法区也是垃圾回收的区域之一,主要回收废弃的类元数据(如类被卸载时),但回收频率较低。

2. 线程私有区

线程私有区包括程序计数器、虚拟机栈、本地方法栈,每个线程都有独立的一份,线程创建时分配,线程结束时释放,不会出现线程安全问题。

(1)程序计数器(Program Counter Register):程序计数器是JVM中最小的内存区域,用于记录当前线程执行的字节码行号指示器,线程切换后能恢复到之前的执行位置。若线程执行的是Java方法,程序计数器存储当前字节码的行号;若执行的是本地方法(Native方法),程序计数器的值为undefined。

程序计数器是JVM中唯一不会出现OOM异常的区域,因为它的大小是固定的,仅用于存储行号信息。

(2)虚拟机栈(VM Stack):虚拟机栈用于存储方法调用的栈帧(每个方法调用对应一个栈帧入栈,方法执行完毕对应栈帧出栈),栈帧包含局部变量表、操作数栈、方法返回地址、异常处理表等。

  • 局部变量表:用于存储方法中的局部变量(包括参数、局部变量),大小在编译时确定,运行时不可改变;

  • 操作数栈:用于存储方法执行过程中的操作数(如常量、变量值),供指令执行时使用;

  • 方法返回地址:用于存储方法执行完毕后,返回的调用者位置;

  • 异常处理表:用于存储方法中的异常处理信息,当出现异常时,JVM通过异常处理表找到对应的异常处理代码。

虚拟机栈的大小可通过JVM参数配置(如-Xss),若方法调用层级过深(如递归调用未终止),会导致栈帧溢出,抛出StackOverflowError异常;若虚拟机栈无法分配足够的内存,会抛出OOM异常。

(3)本地方法栈(Native Method Stack):本地方法栈与虚拟机栈功能类似,但专门为本地方法(Native Method,如C/C++编写的方法)提供服务。本地方法栈的实现由JVM厂商决定,有的JVM(如HotSpot)将本地方法栈与虚拟机栈合并实现。

本地方法栈也会出现StackOverflowError和OOM异常,与虚拟机栈的异常场景类似。

2.1.3 执行引擎(Execution Engine)

执行引擎是JVM的"运算核心",负责将加载到内存中的Java字节码转换为本地机器指令(对应操作系统的CPU指令)并执行。执行引擎的核心执行方式有两种,JVM默认采用"解释器 + 即时编译器(JIT)"的混合模式,兼顾启动速度和运行效率。

1. 解释器(Interpreter)

解释器的工作原理是逐行解析Java字节码,每解析一行就转换为对应的机器指令执行,无需等待全部字节码解析完成。其优点是启动速度快,适合程序冷启动阶段(如刚启动的Java应用),能快速响应执行请求;缺点是执行效率低,对于频繁执行的代码(热点代码),会重复解析和转换,造成资源浪费。

2. 即时编译器(Just-In-Time Compiler,JIT)

即时编译器的工作原理是监测程序运行过程,识别热点代码(频繁执行的方法、循环体),将其一次性编译为本地机器码并缓存,后续执行该代码时,直接调用缓存的机器码,无需再通过解释器解析。其优点是执行效率高,机器码直接与CPU交互,避免重复解析,能显著提升程序运行速度;缺点是编译需要耗时,启动速度慢,不适合冷启动阶段。

3. 混合执行模式的优势

JVM启动初期,通过解释器快速执行程序,保证启动速度;运行一段时间后,JIT编译器将热点代码编译为机器码,保证运行效率。这种"解释器 + JIT"的混合模式,兼顾了"冷启动快"和"运行效率高"两大需求,是主流JVM(如HotSpot)的默认执行模式。

此外,JIT编译器还会对热点代码进行优化(如循环展开、常量折叠、方法内联等),进一步提升代码的执行效率。例如,对于频繁调用的简单方法,JIT会将方法体嵌入到调用者代码中,减少方法调用的开销。

2.1.4 本地方法接口(Native Method Interface,JNI)

本地方法接口是JVM与本地方法(C/C++编写的方法)交互的桥梁,负责将Java方法调用转换为本地方法调用,反之亦然。Java语言本身无法直接操作底层硬件(如磁盘、内存、CPU),通过本地方法接口,Java程序可以调用C/C++编写的本地方法,实现对底层硬件的操作,弥补Java语言的局限性。

本地方法接口的核心作用是:

  • 调用本地方法:Java程序通过JNI调用本地方法,获取底层硬件资源的访问权限;

  • 传递参数和返回值:在Java方法和本地方法之间传递参数和返回值,完成数据交互;

  • 处理异常:将本地方法抛出的异常转换为Java异常,供Java程序捕获和处理。

常见的本地方法如System.currentTimeMillis()、Runtime.getRuntime().exec()等,其底层都是通过C/C++实现的,通过JNI接口供Java程序调用。

2.2 JVM的垃圾回收机制(GC)

垃圾回收(Garbage Collection,GC)是JVM的核心功能之一,负责自动回收程序运行过程中产生的无用对象,释放内存资源,避免内存泄漏和OOM异常。JVM的垃圾回收机制无需开发者手动管理内存(C/C++需要手动分配和释放内存),极大地降低了开发难度,提升了程序的稳定性。

2.2.1 垃圾回收的核心概念

1. 垃圾对象的定义

垃圾对象是指程序运行过程中,不再被任何引用指向的对象,这些对象无法被程序访问,占用的内存资源可以被回收。例如:

Object obj = new Object();

obj = null;

当obj被赋值为null后,之前new出来的Object对象不再被任何引用指向,成为垃圾对象,等待GC回收。

2. 垃圾对象的判断方法

JVM判断垃圾对象的方法主要有两种:引用计数法和可达性分析算法。

(1)引用计数法:为每个对象设置一个引用计数器,当对象被引用时,计数器加1;当引用失效时,计数器减1;当计数器为0时,判断为垃圾对象。这种方法实现简单、效率高,但无法解决循环引用的问题(如两个对象相互引用,计数器都为1,但都无法被访问),因此主流JVM(如HotSpot)不采用这种方法。

(2)可达性分析算法:以"GC Roots"为起点,向下遍历对象引用链,若某个对象无法通过任何引用链到达GC Roots,则判断为垃圾对象。GC Roots的对象包括:虚拟机栈中的局部变量、方法区中的静态变量、本地方法栈中的本地方法引用、活跃线程等。这种方法能解决循环引用的问题,是主流JVM采用的垃圾判断方法。

3. 引用类型

Java中的引用分为四种类型,不同类型的引用对GC的影响不同,从强到弱依次为:

  • 强引用:最常见的引用类型(如Object obj = new Object()),只要强引用存在,GC就不会回收被引用的对象,即使内存不足,也会抛出OOM异常,不会回收强引用对象。

  • 软引用:通过SoftReference类实现,当内存充足时,GC不回收软引用对象;当内存不足时,GC会回收软引用对象,适合用于缓存场景(如图片缓存)。

  • 弱引用:通过WeakReference类实现,无论内存是否充足,GC都会回收弱引用对象,适合用于临时对象存储,生命周期较短。

  • 虚引用:通过PhantomReference类实现,虚引用无法访问对象本身,仅用于监听对象的GC回收事件,当对象被GC回收时,会收到一个通知,适合用于资源释放场景。

2.2.2 垃圾回收算法

JVM的垃圾回收算法主要有四种:标记-清除算法、复制算法、标记-整理算法、分代收集算法,不同算法适用于不同的场景,各有优缺点。

1. 标记-清除算法(Mark-Sweep)

标记-清除算法是最基础的垃圾回收算法,分为"标记"和"清除"两个阶段:

  • 标记阶段:通过可达性分析算法,标记出所有存活对象(非垃圾对象);

  • 清除阶段:遍历内存区域,清除所有未被标记的垃圾对象,释放内存资源。

优点:实现简单,无需移动对象,适合存活对象较多的场景(如老年代);

缺点:清除后会产生大量的内存碎片,后续分配大对象时,可能因无法找到连续的内存空间而触发GC,影响程序性能。

2. 复制算法(Copying)

复制算法的核心是将内存区域分为两个大小相等的区域(如From区和To区),每次只使用其中一个区域:

  • 标记阶段:标记出当前区域中的存活对象;

  • 复制阶段:将存活对象复制到另一个未使用的区域,然后清除当前区域的所有对象;

  • 切换阶段:切换两个区域的角色,下次GC时使用另一个区域。

优点:没有内存碎片,分配内存时只需移动指针即可,效率高,适合存活对象较少的场景(如新生代);

缺点:内存利用率低,仅能使用一半的内存区域,且复制对象时会产生一定的开销。

3. 标记-整理算法(Mark-Compact)

标记-整理算法是标记-清除算法的优化版本,分为"标记""整理""清除"三个阶段:

  • 标记阶段:标记出所有存活对象;

  • 整理阶段:将所有存活对象移动到内存区域的一端,紧凑排列,消除内存碎片;

  • 清除阶段:清除内存区域另一端的所有垃圾对象,释放内存资源。

优点:没有内存碎片,内存利用率高,适合存活对象较多的场景(如老年代);

缺点:移动对象时会产生较大的开销,影响程序的运行性能。

4. 分代收集算法(Generational Collection)

分代收集算法是主流JVM(如HotSpot)采用的垃圾回收算法,核心是根据对象的生命周期,将堆内存分为新生代和老年代,针对不同代的特点采用不同的垃圾回收算法,兼顾效率和内存利用率。

  • 新生代:对象生命周期短,存活对象少,采用复制算法,GC频率高,耗时短(Minor GC);

  • 老年代:对象生命周期长,存活对象多,采用标记-清除算法或标记-整理算法,GC频率低,耗时长(Full GC)。

分代收集算法的优势在于,针对不同代的对象特点选择合适的算法,避免了单一算法的缺点,提升了垃圾回收的效率和性能。

2.2.3 常见垃圾收集器

垃圾收集器是垃圾回收算法的具体实现,不同的JVM实现有不同的垃圾收集器,主流的垃圾收集器包括:

1. Serial GC(串行收集器)

Serial GC是最基础的垃圾收集器,采用单线程执行垃圾回收,GC期间会暂停所有用户线程(STW,Stop The World),适合单CPU、内存较小的场景(如嵌入式设备)。优点是实现简单、开销小;缺点是STW时间长,影响程序响应速度,不适合高并发、大内存场景。

2. Parallel GC(并行收集器)

Parallel GC是多线程垃圾收集器,采用多线程执行垃圾回收,GC期间仍会暂停用户线程,但STW时间比Serial GC短,适合多CPU、大内存、高吞吐量的场景(如批处理任务)。Parallel GC是JDK8的默认垃圾收集器,核心目标是提升吞吐量(程序运行时间/总时间)。

3. CMS GC(并发标记清除收集器)

CMS GC是并发垃圾收集器,核心目标是降低STW时间,适合低延迟、高并发的场景(如Web应用)。CMS GC分为四个阶段:初始标记(STW)、并发标记(不STW)、重新标记(STW)、并发清除(不STW),其中仅初始标记和重新标记阶段会暂停用户线程,STW时间较短。优点是延迟低,不影响程序响应;缺点是内存碎片多、CPU开销大,不适合大内存场景。

4. G1 GC(垃圾优先收集器)

G1 GC是JDK9及以后的默认垃圾收集器,结合了分代收集和区域化内存管理的特点,将堆内存分为多个大小相等的Region(区域),每个Region可以是新生代或老年代,动态调整Region的角色。G1 GC的核心目标是在保证低延迟的同时,提升吞吐量,适合大内存、高并发的场景(如大数据应用)。优点是没有内存碎片、STW时间可控制、内存利用率高;缺点是实现复杂、CPU开销大。

5. ZGC/Shenandoah GC(超低延迟收集器)

ZGC(JDK11+)和Shenandoah GC(OpenJDK)是针对超低延迟场景设计的垃圾收集器,STW时间可控制在毫秒级甚至微秒级,适合延迟敏感的场景(如金融交易、实时计算)。两者都采用了并发标记-整理算法,支持大内存(最大可支持数TB内存),但实现复杂,目前在生产环境中的应用还不够广泛。

2.3 JVM的常见实现版本

JVM的实现需遵循《Java虚拟机规范》,不同厂商提供了不同的JVM实现版本,各有特点,适用于不同的场景。主流的JVM实现版本包括:

1. Oracle HotSpot JVM

HotSpot JVM是Oracle公司开发的JVM实现,是目前最流行、应用最广泛的JVM版本,也是JDK默认的JVM实现(JDK6及以后)。HotSpot JVM的核心特点是:采用"解释器 + JIT"混合执行模式,支持多种垃圾收集器,性能优异,兼容性好,适合各种Java应用场景(Web开发、移动开发、大数据等)。

HotSpot JVM的优势在于:优化成熟,针对不同场景提供了多种垃圾收集器和优化策略;社区活跃,更新迭代快,不断修复漏洞、提升性能;支持多种操作系统和硬件架构,兼容性强。

2. IBM OpenJ9 JVM

OpenJ9 JVM是IBM公司开发的JVM实现,开源后由Eclipse基金会维护,核心特点是轻量级、低内存占用、启动速度快,适合嵌入式系统、云原生应用、微服务等场景。OpenJ9 JVM的垃圾收集器(如Metronome GC)在低延迟、低内存占用方面表现优异,与IBM的WebSphere应用服务器兼容性好。

3. GraalVM

GraalVM是Oracle公司开发的新一代JVM,支持多种编程语言(Java、Scala、Kotlin、JavaScript等),核心特点是支持AOT( Ahead-of-Time)编译,可将Java字节码提前编译为机器码,提升程序启动速度和运行效率。GraalVM还支持即时编译优化,性能比HotSpot JVM更优,适合高性能、多语言混合开发的场景。

4. Azul Zing JVM

Zing JVM是Azul Systems公司开发的JVM实现,专门针对高并发、大内存、低延迟的场景设计,核心特点是支持超大堆内存(最大可支持数TB),STW时间极短(毫秒级),适合金融、电商、大数据等对延迟要求极高的应用。Zing JVM的垃圾收集器(C4 GC)采用并发标记-整理算法,无需暂停用户线程即可完成垃圾回收,性能表现优异,但属于商业版JVM,需要付费使用。

2.4 JVM的实战应用:参数配置与问题排查

对于Java开发者而言,掌握JVM的参数配置和问题排查方法,是优化程序性能、解决运行故障的关键。本节将介绍JVM的核心参数配置、性能调优思路,以及常见问题(OOM、GC异常)的排查方法。

2.4.1 JVM核心参数配置

JVM参数分为三类:标准参数(-)、非标准参数(-X)、高级参数(-XX),其中标准参数和非标准参数较为常用,高级参数用于精细调优,不同JVM实现的参数可能略有差异。

1. 堆内存参数(必配)

堆内存是JVM内存管理的核心,合理配置堆内存参数,能有效避免OOM异常,提升程序性能。核心堆内存参数如下:

  • -Xms:初始堆内存大小,建议与-Xmx一致,避免内存抖动,例如-Xms6g(8G服务器推荐配置);

  • -Xmx:最大堆内存大小,不超过物理内存的70%,例如-Xmx6g;

  • -Xmn:新生代大小,建议为堆内存的1/3~1/2,例如-Xmn2g(Eden+2个Survivor);

  • -XX:SurvivorRatio:Eden区与单个Survivor区的比例,默认8:1:1,例如-XX:SurvivorRatio=8;

  • -XX:MetaspaceSize:元空间初始大小(JDK8+),例如-XX:MetaspaceSize=256m;

  • -XX:MaxMetaspaceSize:元空间最大大小,避免溢出,例如-XX:MaxMetaspaceSize=512m;

  • -XX:NewRatio:老年代与新生代的比例,优先级低于-Xmn,例如-XX:NewRatio=2(老:新=2:1)。

2. 垃圾收集器参数(按需选择)

根据应用场景选择合适的垃圾收集器,核心参数如下:

(1)高吞吐量场景(批处理、后台任务)→ ParallelGC(JDK8默认)

-XX:+UseParallelGC -XX:+UseParallelOldGC

-XX:ParallelGCThreads=4 # GC线程数(默认=CPU核心数)

-XX:MaxGCPauseMillis=100 # 目标最大GC停顿时间(软限制)

(2)低停顿场景(接口、Web应用)→ G1GC(JDK9+默认,JDK8推荐)

-XX:+UseG1GC

-XX:G1HeapRegionSize=16m # Region大小(1M~32M,2的幂)

-XX:MaxGCPauseMillis=50 # 目标停顿时间(核心参数)

-XX:G1NewSizePercent=5 # 新生代最小比例(默认5%)

-XX:G1MaxNewSizePercent=60 # 新生代最大比例(默认60%)

(3)超低停顿场景(延迟敏感场景)→ ZGC(JDK11+)

-XX:+UseZGC -Xmx6g

-XX:ZGCParallelGCThreads=4

3. 其他关键参数

  • -XX:+PrintGCDetails:打印GC详细日志,调试时启用;

  • -XX:+PrintGCTimeStamps:打印GC时间戳,方便定位GC发生的时间;

  • -XX:+HeapDumpOnOutOfMemoryError:OOM异常时,自动生成堆转储文件(heap dump),用于排查OOM原因;

  • -Xss:虚拟机栈大小,默认1M,用于控制方法调用层级,例如-Xss2m;

  • -XX:HeapDumpPath:指定堆转储文件的存储路径,例如-XX:HeapDumpPath=/tmp/heapdump.hprof。

2.4.2 JVM性能调优思路

JVM性能调优的核心目标是减少GC停顿时间、降低GC频率、避免内存泄漏,最终提升应用吞吐量和稳定性。调优需遵循"监控→分析→优化→验证"的闭环,结合应用场景针对性调整,具体思路如下:

1. 调优前提(避免盲目调优)

  • 明确性能指标:如GC停顿≤100ms、GC频率≤5次/分钟、堆内存使用率稳定在70%以下;

  • 先解决代码问题:内存泄漏、频繁创建大对象、死锁等代码级问题,优先于JVM参数调优;

  • 基于监控数据:通过JVM工具(jstat、jmap、Arthas)获取真实运行数据,而非凭经验猜参。

2. 核心调优维度

  • 堆内存分配:合理设置-Xms、-Xmx、-Xmn等参数,减少GC频率,避免OOM;

  • 垃圾收集器选择:根据应用场景选择合适的垃圾收集器,兼顾吞吐量和延迟;

  • 内存泄漏排查:分析堆Dump文件,检查大对象、长生命周期对象,及时释放无用引用;

  • 新生代优化:调整Eden/Survivor比例、晋升阈值,让对象在Minor GC中快速回收;

  • 老年代优化:控制大对象直接进入老年代,调整GC触发时机,减少Full GC频率。

2.4.3 常见问题排查方法

1. OOM异常排查

OOM异常是JVM最常见的问题之一,主要分为堆内存OOM、元空间OOM、虚拟机栈OOM等,排查步骤如下:

(1)开启堆转储:配置-XX:+HeapDumpOnOutOfMemoryError参数,OOM时自动生成堆转储文件;

(2)分析堆转储文件:使用JDK自带的jhat工具,或第三方工具(如MAT、VisualVM),分析堆内存中的对象分布,找到占用内存最多的对象;

定位问题原因:判断是内存泄漏(无用对象无法回收)还是内存不足(堆内存设置过小);若是内存泄漏,找到泄漏的引用链,修复代码(如关闭未释放的资源、清除无效引用);若是内存不足,合理调整-Xms、-Xmx参数,扩大堆内存。

(4)验证修复效果:修改代码或调整参数后,重启应用,通过监控工具观察堆内存使用情况,确认OOM异常不再出现。

示例:若堆转储文件显示大量ArrayList对象未被回收,且引用链指向一个静态集合,说明存在内存泄漏------静态集合持有对象引用,导致对象无法被GC回收,此时需在使用完毕后清空集合,释放引用。

2. GC异常排查(频繁GC、GC停顿过长)

GC异常主要表现为GC频率过高(如每分钟超过10次)、GC停顿时间过长(如Full GC超过1秒),会导致应用响应缓慢、吞吐量下降,排查步骤如下:

(1)开启GC日志:配置-XX:+PrintGCDetails、-XX:+PrintGCTimeStamps参数,记录GC发生的时间、类型、停顿时间、内存变化等信息;

(2)分析GC日志:通过GC日志判断异常类型------是Minor GC频繁,还是Full GC频繁;若是Minor GC频繁,可能是新生代设置过小,或频繁创建短期对象;若是Full GC频繁,可能是老年代内存不足、大对象直接进入老年代,或内存泄漏;

(3)针对性优化:

  • Minor GC频繁:增大新生代大小(调整-Xmn),优化代码减少短期对象的频繁创建(如使用对象池复用对象);

  • Full GC频繁:检查是否有大对象直接进入老年代(可通过-XX:PretenureSizeThreshold参数控制大对象阈值),排查内存泄漏,或增大老年代内存(调整-Xmx、-XX:NewRatio);

  • GC停顿过长:更换垃圾收集器(如将Serial GC改为G1 GC),调整GC线程数(-XX:ParallelGCThreads),或优化堆内存分配,减少GC扫描范围。

示例:若GC日志显示每次Full GC停顿时间超过2秒,且老年代内存使用率快速达到100%,结合堆转储文件发现大量长生命周期对象未被回收,说明存在内存泄漏,需定位泄漏点并修复。

3. 栈溢出(StackOverflowError)排查

栈溢出主要是由于方法调用层级过深(如无限递归),导致虚拟机栈无法容纳更多栈帧,排查步骤如下:

(1)查看异常日志:StackOverflowError异常会伴随方法调用栈信息,通过日志定位到具体的递归方法或深层调用链路;

(2)分析代码问题:检查是否存在无限递归(如递归未设置终止条件),或方法调用层级过多(如多层嵌套调用);

(3)修复优化:修改代码,添加递归终止条件,或减少方法调用层级(如将深层递归改为迭代);若确实需要深层调用,可适当增大虚拟机栈大小(调整-Xss参数)。

示例:若异常日志显示某递归方法调用次数超过1000次,且未设置终止条件,需添加终止逻辑,避免无限递归。

4. 常用排查工具

排查JVM问题时,合理使用工具能提高效率,常用工具分为两类:JDK自带工具和第三方工具。

(1)JDK自带工具(无需额外安装,便捷高效):

  • jstat:实时监控JVM的GC情况、内存使用情况,例如jstat -gc 进程ID 1000(每隔1秒输出一次GC信息);

  • jmap:生成堆转储文件、查看堆内存对象分布,例如jmap -dump:format=b,file=heapdump.hprof 进程ID(生成堆转储文件);

  • jhat:分析堆转储文件,例如jhat heapdump.hprof(启动本地服务,通过浏览器查看堆内存详情);

  • jstack:查看线程栈信息,排查死锁、线程阻塞问题,例如jstack 进程ID(输出所有线程的调用栈);

  • jconsole:图形化监控工具,实时查看JVM内存、GC、线程等信息,启动命令:jconsole。

(2)第三方工具(功能更强大,适合复杂问题排查):

  • MAT(Memory Analyzer Tool):专业的堆内存分析工具,能快速定位内存泄漏、大对象问题,支持多种堆转储文件格式;

  • VisualVM:集成多种功能(内存监控、GC监控、线程监控、抽样分析),图形化界面直观,适合日常开发和问题排查;

  • Arthas:阿里巴巴开源的Java诊断工具,无需重启应用,即可实时查看JVM状态、排查代码问题,适合生产环境排查。

第三章 深度解析JRE:Java程序的运行基石

JRE作为Java程序的运行核心,是连接JVM与Java应用的桥梁,它为Java程序提供了运行所需的基础环境和核心依赖,确保编译后的字节码能够正常执行。很多开发者往往忽视JRE的作用,认为"只要掌握JDK和JVM就足够",但实际上,JRE的类库、运行时工具直接影响Java程序的稳定性和兼容性。本章将从JRE的核心组成、工作机制、版本迭代、实战应用等方面,深入解析JRE的核心价值,帮助读者全面理解JRE在Java技术体系中的作用。

3.1 JRE的核心组成

JRE(Java Runtime Environment)的核心定位是"支撑Java程序运行的最小环境",其组成部分可分为三大类:JVM实例、Java核心类库、运行时辅助工具,三者协同工作,为Java程序提供完整的运行支持。

3.1.1 JVM实例(核心执行组件)

JRE包含一个JVM实例,这是Java程序能够运行的核心前提。当用户启动一个Java程序(如通过java命令执行.jar文件)时,JRE会启动一个JVM实例,负责加载字节码、执行指令、内存管理等工作;当程序执行完毕,JVM实例会终止,释放占用的内存资源。

需要注意的是,JRE中的JVM实例与JDK中的JVM实例本质上是一致的------JDK中的JVM用于开发、调试时的程序执行,而JRE中的JVM仅用于运行已编译好的程序,两者遵循相同的《Java虚拟机规范》,实现版本也完全一致(如HotSpot JVM)。

此外,JRE中的JVM会根据操作系统自动适配,例如Windows系统的JRE会启动Windows版本的HotSpot JVM,Linux系统则启动Linux版本的JVM,确保Java程序的跨平台运行。

3.1.2 Java核心类库(核心依赖组件)

Java核心类库是JRE的核心组成部分,也是Java程序运行的基础依赖,它提供了Java程序所需的所有基础功能,开发者无需重复编写这些功能,直接调用类库中的方法即可完成开发。Java核心类库主要包含以下几大模块,覆盖了程序运行的各个场景:

1. 基础核心模块(java.lang包)

java.lang包是Java最核心的包,无需手动导入,默认自动加载,包含了Java程序运行所需的基础类,例如:

  • 基本数据类型包装类(Integer、Long、Boolean等):用于封装基本数据类型,提供面向对象的操作方式;

  • Object类:所有Java类的父类,提供equals()、hashCode()、toString()等基础方法;

  • String类:用于字符串处理,提供字符串拼接、截取、查找等方法;

  • 线程相关类(Thread、Runnable、ThreadLocal等):用于实现多线程编程;

  • 异常相关类(Exception、Error等):用于异常处理,保障程序稳定运行。

java.lang包是Java程序的"基石",任何Java程序都离不开这个包的支持,一旦该包出现问题,程序将无法正常运行。

2. 集合框架模块(java.util包)

java.util包提供了一系列集合类,用于存储和操作数据,解决了Java中数组的局限性(固定大小、无法动态扩展),核心类包括:

  • List接口(ArrayList、LinkedList):用于存储有序、可重复的元素;

  • Set接口(HashSet、TreeSet):用于存储无序、不可重复的元素;

  • Map接口(HashMap、TreeMap):用于存储键值对数据,实现快速查找;

  • 工具类(Collections、Arrays):提供集合排序、数组操作等辅助方法。

集合框架是Java程序处理数据的核心工具,广泛应用于Web开发、大数据处理等场景,其性能直接影响程序的运行效率。

3. IO操作模块(java.io包)

java.io包提供了文件操作、输入输出流操作的相关类,用于实现Java程序与外部设备(磁盘、网络)的数据交互,核心类包括:

  • 字节流(InputStream、OutputStream):用于处理字节数据(如图片、视频);

  • 字符流(Reader、Writer):用于处理字符数据(如文本文件);

  • 文件操作类(File、FileInputStream、FileOutputStream):用于操作本地文件;

  • 缓冲流(BufferedInputStream、BufferedWriter):用于提升IO操作效率。

IO操作是Java程序的常见场景,无论是读取配置文件、写入日志,还是网络通信,都需要依赖java.io包的支持。

4. 网络通信模块(java.net包)

java.net包提供了网络通信相关的类,用于实现Java程序的网络连接、数据传输,支持TCP/IP、UDP等协议,核心类包括:

  • Socket、ServerSocket:用于实现TCP协议的客户端和服务器端通信;

  • DatagramSocket、DatagramPacket:用于实现UDP协议的数据传输;

  • URL、URLConnection:用于访问网络资源(如HTTP请求)。

随着Web开发、分布式系统的普及,网络通信模块的作用越来越重要,是Java程序实现跨节点交互的核心依赖。

5. 其他核心模块

除了上述模块,Java核心类库还包含java.math(数学运算)、java.security(安全相关)、java.time(日期时间处理)等模块,覆盖了Java程序运行的各个场景,形成了完整的依赖体系。

需要注意的是,JRE中的核心类库是"精简版"的------仅包含程序运行所需的类,不包含开发、编译相关的类(如javac编译器相关类);而JDK中的核心类库是"完整版"的,包含了运行和开发所需的所有类。

3.1.3 运行时辅助工具(辅助支撑组件)

JRE中包含一系列运行时辅助工具,用于支撑Java程序的正常运行,这些工具通常隐藏在JRE的bin目录下,用户无需手动调用,由JVM自动触发或通过命令行调用,核心工具包括:

1. java.exe(Java运行工具)

java.exe是JRE中最核心的工具,用于启动JVM实例,执行Java字节码文件。用户通过命令行输入"java 类名"或"java -jar jar包名",本质上是调用java.exe工具,启动JVM并加载执行对应的字节码。

2. javaw.exe(无控制台的Java运行工具)

javaw.exe与java.exe功能类似,用于启动JVM执行Java程序,但区别在于:javaw.exe启动程序后,不会弹出控制台窗口,适合运行桌面应用(如Java Swing开发的桌面程序),避免控制台窗口影响用户体验。

3. keytool.exe(密钥管理工具)

keytool.exe用于管理Java程序的密钥、证书,主要用于安全相关场景(如HTTPS通信、数字签名),可以生成密钥对、导入导出证书、查看证书信息等。

4. policytool.exe(安全策略配置工具)

policytool.exe用于配置Java程序的安全策略,控制Java程序对系统资源(如文件、网络)的访问权限,避免恶意Java程序破坏系统安全。

5. rmid.exe(RMI注册表工具)

rmid.exe用于启动RMI(远程方法调用)注册表,支持Java程序的远程方法调用,是分布式Java应用的辅助工具。

这些运行时辅助工具虽然不直接参与字节码的执行,但它们为Java程序的安全运行、分布式部署提供了重要支撑,是JRE不可或缺的组成部分。

3.2 JRE的工作机制

JRE的核心工作是"为Java程序提供运行环境,确保字节码能够正常执行",其工作机制可概括为"启动JVM→加载类库→执行字节码→终止JVM"四个步骤,整个过程由JRE自动完成,无需用户干预。

1. 启动JVM实例

当用户通过java命令启动Java程序时,JRE会首先启动一个JVM实例,同时初始化JVM的核心组件(类加载子系统、运行时数据区、执行引擎等),为字节码的加载和执行做好准备。JVM实例的启动参数由JRE默认配置,也可通过命令行参数(如-Xms、-Xmx)手动调整。

2. 加载Java核心类库

JVM实例启动后,类加载子系统会首先加载JRE中的Java核心类库(如java.lang包、java.util包),将这些类的字节码加载到运行时数据区的方法区,生成对应的Class对象,供Java程序调用。核心类库的加载优先级最高,由启动类加载器(Bootstrap ClassLoader)负责加载,确保程序运行时能够随时调用基础功能。

3. 加载并执行用户字节码

核心类库加载完成后,JVM会通过类加载器加载用户编写的字节码文件(.class文件或.jar包中的字节码),经过验证、准备、解析、初始化四个步骤,生成Class对象,然后由执行引擎将字节码转换为机器指令,驱动硬件执行。在这个过程中,Java核心类库为用户程序提供基础支持,例如用户程序调用String类的方法时,会直接使用JRE中已加载的String类。

4. 程序终止与JVM销毁

当Java程序执行完毕(如main方法执行结束),或程序抛出未捕获的异常导致终止时,JVM会执行垃圾回收,释放所有占用的内存资源,然后终止JVM实例,JRE的运行过程也随之结束。

需要注意的是,一个JRE可以启动多个JVM实例(即同时运行多个Java程序),每个JVM实例相互独立,各自占用独立的内存空间,互不影响。例如,用户同时运行两个Java程序,JRE会启动两个JVM实例,分别执行对应的程序,程序终止后,各自的JVM实例销毁,释放内存。

3.3 JRE的版本迭代与特性变化

JRE的版本与JDK版本保持一致(如JDK 8对应JRE 8,JDK 11对应JRE 11),其版本迭代主要跟随JDK的迭代,核心变化集中在核心类库的优化、JVM实现的升级、安全性能的提升等方面。以下是几个关键版本的特性变化,帮助读者了解JRE的发展历程:

1. JRE 8(主流版本)

JRE 8是目前应用最广泛的版本,对应JDK 8,核心特性包括:

  • 核心类库优化:新增Stream API(java.util.stream包),简化集合数据处理;新增java.time包,替代传统的Date、Calendar类,优化日期时间处理;

  • JVM优化:默认垃圾收集器为Parallel GC,提升吞吐量;支持方法引用、lambda表达式,JIT编译器对这些新特性进行了优化;

  • 安全提升:增强SSL/TLS协议支持,修复多个安全漏洞,提升程序运行安全性;

  • 性能优化:优化IO操作、集合框架的性能,减少内存占用。

JRE 8的优势在于稳定、兼容、性能优异,目前绝大多数Java应用(Web、大数据、桌面应用)都基于JRE 8运行。

2. JRE 9+(模块化版本)

从JDK 9开始,Oracle重构了Java模块化系统(JPMS,Java Platform Module System),JRE也随之进行了重大调整,核心变化包括:

  • 取消独立JRE安装包:JDK 9及以后,不再单独提供独立的JRE安装包,用户需通过JDK精简(如jlink工具)生成自定义的运行时镜像,适配不同场景的运行需求;

  • 核心类库模块化:将Java核心类库拆分为多个模块(如java.base、java.logging、java.net等),用户可以根据需求只加载所需模块,减少运行时内存占用;

  • JVM优化:JDK 9默认垃圾收集器改为G1 GC,提升低延迟性能;JDK 11新增ZGC,支持超大内存和超低延迟;

  • 新增特性:JRE 11支持HTTP/2客户端(java.net.http包),简化HTTP请求操作;支持局部变量类型推断(var关键字),提升开发效率。

JRE 9+的模块化设计,更适合云原生、微服务等场景,能够有效减少运行时内存占用,提升部署效率。

3. JRE的版本兼容性

Java的版本兼容性遵循"向下兼容"原则,即高版本JRE可以运行低版本JDK编译的Java程序,但低版本JRE无法运行高版本JDK编译的程序(除非编译时指定兼容低版本)。例如:

  • JRE 8可以运行JDK 6、JDK 7、JDK 8编译的程序;

  • JRE 7无法运行JDK 8编译的程序(若JDK 8编译时未指定-target 1.7参数)。

因此,在部署Java程序时,需确保JRE版本不低于JDK编译版本,避免出现兼容性问题。

3.4 JRE的实战应用:部署与问题排查

对于Java应用的部署和运维而言,掌握JRE的部署方法、兼容性处理、问题排查技巧,是确保应用稳定运行的关键。本节将结合实战场景,介绍JRE的部署方式、常见问题及排查方法。

3.4.1 JRE的部署方式

JRE的部署方式分为两种:传统部署(基于独立JRE)和模块化部署(基于JDK精简),分别适用于不同的场景。

1. 传统部署(JDK 8及之前)

JDK 8及之前,Oracle提供独立的JRE安装包,部署步骤如下:

(1)下载对应操作系统的JRE安装包(如Windows 64位、Linux 64位);

(2)运行安装包,按照向导完成安装,选择安装路径(如C:\Program Files\Java\jre1.8.0_301);

(3)配置环境变量:设置JAVA_HOME为JRE安装路径,设置Path变量添加%JAVA_HOME%\bin,确保java命令可以正常使用;

(4)验证部署:打开命令行,输入java -version,若显示JRE版本信息,说明部署成功。

这种部署方式适合简单场景(如单机运行桌面应用、小型Web应用),优点是部署简单、无需额外配置,缺点是内存占用较大(加载完整的核心类库)。

2. 模块化部署(JDK 9及以后)

JDK 9及以后,无独立JRE安装包,需通过JDK的jlink工具生成自定义运行时镜像,部署步骤如下:

(1)安装对应版本的JDK(如JDK 11),配置JAVA_HOME环境变量;

(2)使用jlink工具生成运行时镜像,命令格式:jlink --module-path $JAVA_HOME/jmods --add-modules 所需模块 --output 输出路径;

示例:生成包含java.base、java.util、java.io模块的运行时镜像,命令为:jlink --module-path $JAVA_HOME/jmods --add-modules java.base,java.util,java.io --output jre11;

(3)部署运行时镜像:将生成的jre11目录复制到部署服务器,无需额外配置环境变量,直接通过jre11/bin/java命令启动Java程序;

(4)验证部署:进入jre11/bin目录,输入./java -version(Linux)或java -version(Windows),显示版本信息即部署成功。

这种部署方式适合云原生、微服务场景,优点是可以按需加载模块,减少内存占用,提升部署效率;缺点是需要手动配置所需模块,对运维人员有一定要求。

3.4.2 JRE常见问题及排查方法

JRE的常见问题主要集中在兼容性、类库缺失、安全配置三个方面,以下是具体问题及排查方法:

1. 兼容性问题(程序无法启动,提示"Unsupported major.minor version")

(1)问题原因:JRE版本低于JDK编译版本,例如用JDK 8编译的程序,在JRE 7中运行;

(2)排查方法:查看程序的编译版本(可通过javap -verbose 类名查看major version),对比JRE版本,确保JRE版本不低于编译版本;

(3)解决方案:升级JRE版本,或在编译时指定兼容低版本(如JDK 8编译时添加参数-target 1.7 -source 1.7)。

2. 类库缺失问题(程序启动报错"ClassNotFoundException")

(1)问题原因:JRE中缺少程序依赖的类库,可能是核心类库损坏,或程序依赖的第三方类库未正确引入;

(2)排查方法:查看异常日志,定位缺失的类名;若缺失的是核心类(如java.lang.String),说明JRE核心类库损坏,需重新安装JRE或生成运行时镜像;若缺失的是第三方类,说明第三方jar包未正确部署;

(3)解决方案:重新安装JRE或生成运行时镜像;将缺失的第三方jar包放入程序的classpath目录。

3. 安全配置问题(程序无法访问文件、网络,提示安全异常)

(1)问题原因:JRE的安全策略限制了程序对系统资源的访问,例如禁止程序读取本地文件、访问网络;

(2)排查方法:查看异常日志,确认是否为SecurityException;打开JRE的安全策略文件(jre/lib/security/java.policy),检查是否有对应的资源访问权限配置;

(3)解决方案:修改java.policy文件,添加对应的资源访问权限(如允许读取本地文件、访问网络),或使用policytool.exe工具配置安全策略。

4. JRE内存不足问题(程序运行报错"OutOfMemoryError")

(1)问题原因:JRE启动JVM时,堆内存设置过小,无法满足程序运行需求;

(2)排查方法:通过java -Xms -Xmx命令查看当前堆内存配置,结合程序运行情况,判断是否需要扩大堆内存;

(3)解决方案:启动程序时,手动指定堆内存参数,例如java -Xms2g -Xmx4g -jar 程序.jar,扩大堆内存大小。

第四章 深度解析JDK:Java开发的全能工具箱

JDK作为Java开发的核心工具集,是连接开发者与Java技术体系的桥梁,它包含了JRE的所有功能,同时提供了开发、编译、调试、打包等一系列工具,支撑Java程序从编写到部署的全流程开发。对于Java开发者而言,熟练掌握JDK的工具使用和核心特性,是提升开发效率、解决开发问题的关键。本章将从JDK的核心组成、开发工具详解、版本迭代、实战应用等方面,深入解析JDK的核心价值,帮助读者全面掌握JDK的使用方法。

4.1 JDK的核心组成

JDK(Java Development Kit)的核心定位是"Java开发的全能工具箱",其组成部分可概括为"JRE + 开发工具集 + 核心类库源码与文档",三者相互配合,为开发者提供一站式的开发支持。

4.1.1 完整的JRE(运行基础)

JDK包含完整的JRE,这意味着开发者无需额外安装JRE,即可在开发过程中运行Java程序(如调试、测试)。JDK中的JRE与独立JRE完全一致,包含JVM实例、Java核心类库、运行时辅助工具,确保程序能够正常运行。

需要注意的是,JDK中的JRE默认包含开发所需的调试支持(如jdb调试工具依赖的类库),而独立JRE不包含这些调试相关的类库,因此开发者必须安装JDK才能进行调试工作。

4.1.2 核心开发工具集(开发核心)

JDK的核心价值在于其提供的开发工具集,这些工具涵盖了Java程序开发、编译、调试、打包、文档生成等全流程,核心工具均位于JDK的bin目录下,可通过命令行调用,也可被IDE(如IDEA、Eclipse)集成使用。以下是JDK中最常用的核心开发工具:

1. javac(Java编译器)

javac是JDK中最核心的开发工具,用于将Java源码(.java文件)编译为Java字节码(.class文件),是连接Java源码与JVM的关键工具。其核心功能包括:

  • 语法检查:编译时检查Java源码的语法错误(如语法错误、类型不匹配、未定义变量等),若存在错误,会输出错误信息,终止编译;

  • 生成字节码:编译通过后,为每个.java文件生成对应的.class字节码文件,字节码文件包含JVM可执行的指令;

  • 兼容性配置:支持通过-target、-source参数指定编译版本,实现跨版本兼容,例如javac -source 1.8 -target 1.8 Test.java(将源码编译为JRE 8兼容的字节码)。

常用命令格式:javac [选项] 源码文件路径,例如javac Test.java(编译当前目录下的Test.java文件)、javac -d bin src/*.java(将src目录下的所有源码编译到bin目录)。

2. java(Java运行工具)

java工具与JRE中的java.exe功能一致,用于启动JVM实例,执行字节码文件。开发者在开发过程中,可通过java工具运行编译后的程序,进行调试和测试。常用命令格式:java [选项] 类名,例如java Test(运行Test类的main方法)、java -jar 程序.jar(运行打包后的jar包)。

与JRE中的java工具相比,JDK中的java工具支持更多调试相关的选项(如-agentlib、-debug),方便开发者在运行程序时进行调试。

3. javadoc(文档生成工具)

javadoc工具用于生成Java程序的API文档,根据源码中的注释(/** ... */格式的文档注释),自动生成HTML格式的文档,方便开发者查看类、方法、字段的说明,也便于团队协作开发。其核心功能包括:

  • 提取文档注释:提取源码中的文档注释,生成类、方法、字段的说明文档;

  • 生成HTML文档:生成结构化的HTML文档,包含类的继承关系、方法参数、返回值、异常信息等;

  • 自定义配置:支持通过参数配置文档的输出路径、标题、作者等信息。

常用命令格式:javadoc [选项] 源码文件路径,例如javadoc -d doc src/*.java(将src目录下的源码生成文档到doc目录)。

4. jdb(Java调试工具)

jdb是JDK自带的命令行调试工具,用于排查Java程序运行中的错误(如逻辑错误、异常),支持设置断点、查看变量值、单步执行、查看调用栈等调试功能,是开发者排查底层问题的重要工具。常用调试命令包括:

  • stop at 类名:行号:在指定类的指定行设置断点;

  • run:启动程序,开始调试;

  • step:单步执行,进入方法内部;

  • next:单步执行,不进入方法内部;

  • print 变量名:查看指定变量的值;

  • backtrace:查看当前调用栈信息。

常用命令格式:jdb 类名,例如jdb Test(调试Test类)。

5. javap(反编译工具)

javap工具用于对字节码文件(.class文件)进行反编译,将字节码转换为人类可读的汇编指令(JVM指令),帮助开发者查看字节码内容,排查底层问题(如JIT优化效果、方法调用逻辑)。其核心功能包括:

  • 查看字节码指令:反编译字节码文件,显示JVM指令、方法参数、返回值类型等;

  • 查看类结构:显示类的继承关系、接口实现、字段、方法等信息;

  • 查看常量池:显示类的常量池信息(如字符串常量、类引用等)。

常用命令格式:javap [选项] 字节码文件路径,例如javap -verbose Test.class(查看Test.class的详细字节码信息)。

6. jar(打包工具)

jar工具用于将多个字节码文件(.class文件)、资源文件(如配置文件、图片)打包为.jar文件(Java归档文件),方便程序的部署和分发。.jar文件是Java程序的标准部署格式,可通过java -jar命令直接运行。其核心功能包括:

  • 打包文件:将指定目录下的.class文件、资源文件打包为.jar文件;

  • 解压文件:解压.jar文件,查看其中的内容;

  • 查看文件:查看.jar文件中的文件列表,无需解压;

  • 设置主类:指定.jar文件的主类(包含main方法的类),方便通过java -jar命令直接运行。

常用命令格式:jar [选项] 输出jar包路径 输入文件路径,例如jar -cvf Test.jar bin/*.class(将bin目录下的所有.class文件打包为Test.jar)。

7. 其他常用工具

除了上述核心工具,JDK还包含一系列辅助开发工具,例如:

  • jps(Java进程查看工具):查看当前运行的Java进程,例如jps -l(显示进程ID和对应的类名);

  • jstat(JVM监控工具):实时监控JVM的GC情况、内存使用情况,用于开发和调试阶段的性能监控;

  • jmap(堆内存分析工具):生成堆转储文件、查看堆内存对象分布,排查内存泄漏问题;

  • keytool(密钥管理工具):与JRE中的keytool功能一致,用于管理密钥、证书,支持安全相关开发。

4.1.3 核心类库源码与文档(学习与调试基础)

JDK包含了Java核心类库的完整源码和API文档,这是开发者学习Java底层原理、排查问题的重要资源:

1. 核心类库源码

JDK的src.zip文件中包含了所有Java核心类库的源码(如java.lang、java.util、java.io等包的源码),开发者可以通过IDE(如IDEA)关联源码,查看类和方法的实现原理,深入理解Java的底层机制。例如,查看String类的equals()方法源码,了解字符串比较的底层逻辑;查看ArrayList类的add()方法源码,了解集合的扩容机制。

查看源码不仅能帮助开发者理解Java的底层原理,还能在排查问题时,定位到类库中的具体实现,找到问题根源。例如,当程序调用集合类的方法出现异常时,查看源码可以了解异常的触发条件,快速排查问题。

2. API文档

JDK的docs目录中包含了完整的Java API文档,文档详细描述了所有核心类、方法、字段的使用方式,包括参数说明、返回值说明、异常说明、示例代码等。开发者在开发过程中,可通过API文档快速了解类和方法的使用方法,避免记诵大量API,提升开发效率。

此外,Oracle官网也提供了在线API文档,方便开发者随时查阅(如JDK 8 API文档:https://docs.oracle.com/javase/8/docs/api/)。

4.2 JDK的版本迭代与核心特性

JDK的版本迭代速度较快,从1995年的JDK 1.0到目前的JDK 21,每一个版本都带来了新的特性和优化,核心变化集中在开发效率提升、性能优化、新功能支持等方面。以下是几个关键版本的核心特性,帮助读者了解JDK的发展历程和核心功能:

1. JDK 8(主流开发版本)

JDK 8是目前最主流的开发版本,发布于2014年,核心特性包括:

  • Lambda表达式:简化匿名内部类的编写,使代码更简洁,例如List<String> list = Arrays.asList("a", "b"); list.forEach(s -> System.out.println(s));;

  • Stream API:新增java.util.stream包,提供流式数据处理,简化集合操作,支持过滤、映射、排序、聚合等操作,提升开发效率;

  • 方法引用:通过::符号引用已有的方法,简化Lambda表达式的编写,例如list.forEach(System.out::println);;

  • 日期时间API:新增java.time包,替代传统的Date、Calendar类,解决日期时间处理的线程安全问题,提供更简洁、易用的API;

  • 接口默认方法:允许接口中定义默认方法(用default关键字修饰),接口实现类可以不重写该方法,提升接口的扩展性;

  • 性能优化:默认垃圾收集器改为Parallel GC,提升吞吐量;优化JIT编译器,提升代码执行效率。

JDK 8的优势在于稳定、兼容、功能完善,目前绝大多数Java项目(Web、大数据、微服务)都基于JDK 8开发,是Java开发者必须掌握的版本。

2. JDK 9-11(模块化与性能优化版本)

JDK 9-11是Java的重要迭代版本,核心变化集中在模块化、性能优化、新功能支持等方面,其中JDK 11是长期支持版本(LTS),适合生产环境使用:

(1)JDK 9核心特性:

  • 模块化系统(JPMS):将Java核心类库拆分为多个模块,实现模块化开发和部署,减少内存占用;

  • 接口私有方法:允许接口中定义私有方法,用于接口内部方法的复用;

  • 增强的Stream API:新增takeWhile()、dropWhile()等方法,丰富流式处理功能;

  • 多版本兼容JAR:支持在一个JAR包中包含多个版本的类,适配不同版本的JRE。

(2)JDK 10核心特性:

  • 局部变量类型推断(var关键字):允许使用var关键字声明局部变量,编译器自动推断变量类型,简化代码编写,例如var list = new ArrayList<String>();;

  • 垃圾收集器优化:新增G1 GC的并行回收机制,提升GC性能;

  • 线程局部变量优化:优化ThreadLocal的实现,减少内存泄漏风险。

(3)JDK 11核心特性:

  • HTTP/2客户端:新增java.net.http包,支持HTTP/2协议,简化HTTP请求操作,替代传统的HttpURLConnection;

  • 字符串增强:新增isBlank()、lines()、strip()等方法,简化字符串处理;

  • 垃圾收集器优化:默认垃圾收集器改为G1 GC,新增ZGC(实验性),支持超大内存和超低延迟;

  • 移除冗余工具:移除javah、jhat等冗余工具,简化JDK结构;

  • 增强的Lambda表达式:支持var关键字在Lambda参数中使用。

3. JDK 17+(最新长期支持版本)

JDK 17是Java的最新长期支持版本(LTS),发布于2021年,核心特性包括:

  • 密封类(Sealed Classes):限制类的继承,防止滥用继承,提升代码的安全性和可维护性;

  • 增强的switch表达式:支持switch表达式返回值,简化条件判断代码;

  • 垃圾收集器优化:ZGC成为正式特性,支持数TB内存,STW时间控制在毫秒级;

  • 向量API(Vector API):新增java.lang.foreign包,支持向量计算,提升数值计算性能;

  • 增强的反射机制:优化反射性能,支持对密封类的反射访问。

JDK 17的优势在于性能优异、功能强大,适合新的Java项目开发,尤其是对性能和安全性要求较高的场景(如金融、大数据、实时计算)。

4.3 JDK的实战应用:安装、配置与工具使用

对于Java开发者而言,掌握JDK的安装、配置和核心工具的使用,是开展开发工作的前提。本节将结合实战场景,介绍JDK的安装配置方法、核心工具的使用技巧,以及常见问题的排查方法。

4.3.1 JDK的安装与配置

JDK的安装配置步骤适用于Windows、Linux、Mac OS等主流操作系统,以下以Windows系统为例,介绍JDK 8的安装配置方法:

1. 下载JDK安装包

访问Oracle官网(https://www.oracle.com/java/technologies/downloads/),下载对应操作系统的JDK 8安装包(如Windows 64位的jdk-8u301-windows-x64.exe),需要注册Oracle账号后才能下载。

2. 安装JDK

运行安装包,按照向导完成安装,注意以下两点:

  • 选择安装路径:建议安装在非系统盘(如D:\Java\jdk1.8.0_301),避免系统盘空间不足;

  • 取消"安装JRE"选项:JDK已包含完整的JRE,无需额外安装独立JRE,取消该选项可节省磁盘空间。

3. 配置环境变量

环境变量的作用是让系统能够识别JDK的工具(如javac、java),配置步骤如下:

(1)右键"此电脑"→"属性"→"高级系统设置"→"环境变量";

(2)在"系统变量"中,点击"新建",创建JAVA_HOME变量:

变量名:JAVA_HOME

变量值:JDK的安装路径(如D:\Java\jdk1.8.0_301);

(3)找到"Path"变量,点击"编辑",添加以下内容:

%JAVA_HOME%\bin

%JAVA_HOME%\jre\bin(若安装时未取消JRE安装,需添加此路径);

(4)点击"确定",保存环境变量配置。

4. 验证安装配置

打开命令行,输入以下命令,若显示对应版本信息,说明安装配置成功:

  • javac -version:显示javac编译器的版本(如javac 1.8.0_301);

  • java -version:显示Java运行环境的版本(如java version "1.8.0_301")。

Linux、Mac OS系统的安装配置方法类似,核心是下载对应版本的JDK压缩包,解压后配置JAVA_HOME和Path环境变量,具体步骤可参考Oracle官网的安装指南。

4.3.2 JDK核心工具实战使用

以下结合具体场景,介绍JDK核心工具的实战使用方法,帮助开发者快速掌握工具的使用技巧:

1. javac与java工具:编译运行Java程序

场景:编写一个简单的Java程序,编译并运行。

(1)编写源码:创建Test.java文件,内容如下:

public class Test {

public static void main(String[] args) {

System.out.println("Hello, JDK!");

}

}

(2)编译源码:打开命令行,进入Test.java所在目录,输入命令:javac Test.java,编译成功后,生成Test.class字节码文件;

(3)运行程序:输入命令:java Test,输出"Hello, JDK!",说明程序运行成功。

2. javadoc工具:生成API文档

场景:为Test.java生成API文档。

https://app.shangyangjiazu.com

https://ios.shangyangjiazu.com

https://we.shangyangjiazu.com

https://163_www.shangyangjiazu.com

https://m_www.shangyangjiazu.com

https://m.m.shangyangjiazu.com

https://183_www.shangyangjiazu.com

https://wap_www.shangyangjiazu.com

https://web_www.shangyangjiazu.com

https://web.shangyangjiazu.com

https://app_www.shangyangjiazu.com

https://ios_www.shangyangjiazu.com

https://Android.shangyangjiazu.com

https://Android_www.shangyangjiazu.com

https://we_www.shangyangjiazu.com

https://ios_www.shangyangjiazu.com

https://app_www.shangyangjiazu.com

https://wap.shangyangjiazu.com

https://bbs.shangyangjiazu.com

https://bbs_www.shangyangjiazu.com

https://app.aivoyage.cn

https://ios.aivoyage.cn

https://we.aivoyage.cn

https://163_www.aivoyage.cn

https://m_www.aivoyage.cn

https://m.m.aivoyage.cn

https://183_www.aivoyage.cn

https://wap_www.aivoyage.cn

https://web_www.aivoyage.cn

https://web.aivoyage.cn

https://app_www.aivoyage.cn

https://ios_www.aivoyage.cn

https://Android.aivoyage.cn

https://Android_www.aivoyage.cn

https://we_www.aivoyage.cn

https://ios_www.aivoyage.cn

https://app_www.aivoyage.cn

https://wap.aivoyage.cn

https://bbs.aivoyage.cn

https://bbs_www.aivoyage.cn

https://app.jljdgc.cn

https://ios.jljdgc.cn

https://we.jljdgc.cn

https://163_www.jljdgc.cn

https://m_www.jljdgc.cn

https://m.m.jljdgc.cn

https://183_www.jljdgc.cn

https://wap_www.jljdgc.cn

https://web_www.jljdgc.cn

https://web.jljdgc.cn

https://app_www.jljdgc.cn

https://ios_www.jljdgc.cn

https://Android.jljdgc.cn

https://Android_www.jljdgc.cn

https://we_www.jljdgc.cn

https://ios_www.jljdgc.cn

https://app_www.jljdgc.cn

https://wap.jljdgc.cn

https://bbs.jljdgc.cn

https://bbs_www.jljdgc.cn

https://app.tmhenglin.cn

https://ios.tmhenglin.cn

https://we.tmhenglin.cn

https://163_www.tmhenglin.cn

https://m_www.tmhenglin.cn

https://m.m.tmhenglin.cn

https://183_www.tmhenglin.cn

https://wap_www.tmhenglin.cn

https://web_www.tmhenglin.cn

https://web.tmhenglin.cn

https://app_www.tmhenglin.cn

https://ios_www.tmhenglin.cn

https://Android.tmhenglin.cn

https://Android_www.tmhenglin.cn

https://we_www.tmhenglin.cn

https://ios_www.tmhenglin.cn

https://app_www.tmhenglin.cn

https://wap.tmhenglin.cn

https://bbs.tmhenglin.cn

https://bbs_www.tmhenglin.cn

https://app.nnsyqgl.com

https://ios.nnsyqgl.com

https://we.nnsyqgl.com

https://163_www.nnsyqgl.com

https://m_www.nnsyqgl.com

https://m.m.nnsyqgl.com

https://183_www.nnsyqgl.com

https://wap_www.nnsyqgl.com

https://web_www.nnsyqgl.com

https://web.nnsyqgl.com

https://app_www.nnsyqgl.com

https://ios_www.nnsyqgl.com

https://Android.nnsyqgl.com

https://Android_www.nnsyqgl.com

https://we_www.nnsyqgl.com

https://ios_www.nnsyqgl.com

https://app_www.nnsyqgl.com

https://wap.nnsyqgl.com

https://bbs.nnsyqgl.com

https://bbs_www.nnsyqgl.com

https://app.jcddc.com

https://ios.jcddc.com

https://we.jcddc.com

https://163_www.jcddc.com

https://m_www.jcddc.com

https://m.m.jcddc.com

https://183_www.jcddc.com

https://wap_www.jcddc.com

https://web_www.jcddc.com

https://web.jcddc.com

https://app_www.jcddc.com

https://ios_www.jcddc.com

https://Android.jcddc.com

https://Android_www.jcddc.com

https://we_www.jcddc.com

https://ios_www.jcddc.com

https://app_www.jcddc.com

https://wap.jcddc.com

https://bbs.jcddc.com

https://bbs_www.jcddc.com

https://app.wsmuju.com

https://ios.wsmuju.com

https://we.wsmuju.com

https://163_www.wsmuju.com

https://m_www.wsmuju.com

https://m.m.wsmuju.com

https://183_www.wsmuju.com

https://wap_www.wsmuju.com

https://web_www.wsmuju.com

https://web.wsmuju.com

https://app_www.wsmuju.com

https://ios_www.wsmuju.com

https://Android.wsmuju.com

https://Android_www.wsmuju.com

https://we_www.wsmuju.com

https://ios_www.wsmuju.com

https://app_www.wsmuju.com

https://wap.wsmuju.com

https://bbs.wsmuju.com

https://bbs_www.wsmuju.com

https://app.mfkhilsw.cn

https://ios.mfkhilsw.cn

https://we.mfkhilsw.cn

https://163_www.mfkhilsw.cn

https://m_www.mfkhilsw.cn

https://m.m.mfkhilsw.cn

https://183_www.mfkhilsw.cn

https://wap_www.mfkhilsw.cn

https://web_www.mfkhilsw.cn

https://web.mfkhilsw.cn

https://app_www.mfkhilsw.cn

https://ios_www.mfkhilsw.cn

https://Android.mfkhilsw.cn

https://Android_www.mfkhilsw.cn

https://we_www.mfkhilsw.cn

https://ios_www.mfkhilsw.cn

https://app_www.mfkhilsw.cn

https://wap.mfkhilsw.cn

https://bbs.mfkhilsw.cn

https://bbs_www.mfkhilsw.cn

https://app.umswb.com

https://ios.umswb.com

https://we.umswb.com

https://163_www.umswb.com

https://m_www.umswb.com

https://m.m.umswb.com

https://183_www.umswb.com

https://wap_www.umswb.com

https://web_www.umswb.com

https://web.umswb.com

https://app_www.umswb.com

https://ios_www.umswb.com

https://Android.umswb.com

https://Android_www.umswb.com

https://we_www.umswb.com

https://ios_www.umswb.com

https://app_www.umswb.com

https://wap.umswb.com

https://bbs.umswb.com

https://bbs_www.umswb.com

https://app.smxsdezx.cn

https://ios.smxsdezx.cn

https://we.smxsdezx.cn

https://163_www.smxsdezx.cn

https://m_www.smxsdezx.cn

https://m.m.smxsdezx.cn

https://183_www.smxsdezx.cn

https://wap_www.smxsdezx.cn

https://web_www.smxsdezx.cn

https://web.smxsdezx.cn

https://app_www.smxsdezx.cn

https://ios_www.smxsdezx.cn

https://Android.smxsdezx.cn

https://Android_www.smxsdezx.cn

https://we_www.smxsdezx.cn

https://ios_www.smxsdezx.cn

https://app_www.smxsdezx.cn

https://wap.smxsdezx.cn

https://bbs.smxsdezx.cn

https://bbs_www.smxsdezx.cn

(1)修改源码,添加文档注释:

/**

* 测试类,用于演示JDK工具的使用

* @author 开发者

* @version 1.0

*/

public class Test {

/**

* 主方法,程序入口

* @param args 命令行参数

*/

public static void main(String[] args) {

System.out.println("Hello, JDK!");

}

}

(2)生成文档:输入命令:javadoc -d doc Test.java,生成文档到doc目录;

(3)查看文档:打开doc目录下的index.html文件,即可查看生成的API文档。

相关推荐
hef2884 小时前
C语言循环语句详解:实现1到10的打印输出
jvm
m0_748839495 小时前
利用C 图形界面展示MATLAB算法的高效混合编程实践
开发语言·算法·matlab
周末也要写八哥5 小时前
TCP三次握手与四次挥手的过程
java·网络·tcp/ip
@杰克成5 小时前
Java学习31
java·学习·adb
Xin_ye100865 小时前
C# 零基础到精通教程 - 第九章:面向对象编程(高级)——接口、委托与事件
开发语言·c#
weixin_428005305 小时前
C#调用 AI学习从0开始-第1阶段(基础与工具)-第6天流式输出
开发语言·学习·c#·流式输出stream
xiaoshuaishuai85 小时前
C# Anthropic连接超时原因及方案
开发语言·网络·tcp/ip·c#