一、概述

JDK(Java Development Kit)不只是编译器和运行时,它附带了一整套工程化工具。以本机 JDK 17.0.12 为例,bin 目录下共 35 个可执行文件,按功能可分为六大类:

分类 工具数量 核心用途
编译与运行 3 把源码编译成字节码、启动 JVM 执行
类与字节码 9 反汇编、依赖分析、模块化打包、签名
JVM 监控与诊断 11 线上问题排查、性能分析、堆/线程快照
安全与证书 4 密钥管理、Kerberos 认证
文档与开发辅助 6 API 文档、调试、脚本、交互式编程
RMI 与序列化 2 远程方法调用、序列化版本号
辅助工具 2 无障碍辅助

二、编译与运行工具

2.1 javac:Java 编译器

功能:把 .java 源码编译成 .class 字节码。

# 基本用法
javac Hello.java                    # 编译单个文件,输出 Hello.class
javac -d out src/*.java             # 编译 src 下所有 java,结构化输出到 out/
javac -cp lib/*:src -d out src/*.java  # 指定 classpath(依赖的 jar 或其他类)
javac -encoding UTF-8 Hello.java   # 指定源码编码(中文环境常见问题)
javac --release 8 Hello.java       # 交叉编译,生成兼容 Java 8 的字节码
javac -Xlint:all Hello.java        # 开启所有编译器警告
javac -g Hello.java                # 生成带调试信息的 class(行号、局部变量名)
javac -proc:none Hello.java        # 关闭注解处理

常用参数速查

参数 作用
-d <目录> 指定 class 输出目录,按包结构建子目录
-cp/-classpath 指定编译时依赖的类路径
--release <N> 兼容目标版本的 API(比 -source/-target 更安全)
-encoding 源码文件编码,Windows 下默认 GBK,通常指定 UTF-8
-Xlint:all 开启全部警告(unchecked/deprecation/rawtypes 等)
-g 生成完整调试信息,配合 jdb 断点调试
-parameters 在 class 中保留方法参数名(反射/框架能拿到参数名)
-processor 指定注解处理器

典型排错

# 中文注释报乱码错误
javac -encoding UTF-8 Hello.java

# 找不到依赖类(比如 Guava)
javac -cp lib/guava-31.1.jar App.java

# 代码里用了 Java 11 的 API,但要兼容 Java 8
javac --release 8 App.java   # 编译期就会报:String.isBlank() 在 Java 8 不存在

2.2 java:启动 JVM 执行

功能:启动 Java 虚拟机,加载主类执行 main 方法。

# 基本用法
java Hello                              # 执行当前目录的 Hello.class(不要写 .class 后缀)
java -cp out com.example.Hello          # 指定类路径 + 全限定类名
java -jar app.jar                       # 执行可执行 jar(MANIFEST.MF 里指定了 Main-Class)
java -Xmx2g -Xms512m -jar app.jar      # 设置堆内存:最大 2G,初始 512M

# 常用 JVM 参数
java -XX:+PrintGCDetails -jar app.jar  # 打印 GC 详情日志
java -XX:+HeapDumpOnOutOfMemoryError -jar app.jar  # OOM 时自动 dump 堆
java -Dfile.encoding=UTF-8 -jar app.jar  # 设置系统属性
java -javaagent:agent.jar -jar app.jar    # 挂载 Java Agent

JVM 内存参数(高频面试/实战)

参数 作用 建议值
-Xms<size> 堆初始大小 生产环境通常设成和 -Xmx 一样,避免堆动态扩容
-Xmx<size> 堆最大大小 物理内存的 60%-70%,留足给元空间+堆外+OS
-Xmn<size> 新生代大小 默认约堆的 1/3,G1 收集器不建议手动设
-XX:MetaspaceSize 元空间初始大小 Java 8+ 用元空间替代永久代
-XX:MaxMetaspaceSize 元空间最大大小 默认无上限,建议设置防止内存泄漏
-Xss<size> 每个线程栈大小 默认 1M,递归很深的场景可以调大
-XX:+UseG1GC 使用 G1 垃圾收集器 Java 9+ 默认,大堆(>4G)推荐
-XX:+UseZGC 使用 ZGC Java 15+,超低停顿(<10ms),大堆首选

2.3 javaw:无控制台启动

功能:和 java 完全一样,区别是不会弹出/占用命令行窗口。

适用场景:桌面 GUI 程序(Swing/JavaFX)、Windows 后台服务。

# 启动 Swing GUI 程序,不阻塞命令行
javaw -jar my-gui-app.jar

三、类与字节码工具

3.1 javap:字节码反汇编(必学)

功能:把 .class 字节码反汇编成人类可读的 JVM 指令,是理解 Java 编译器行为、排查语法糖真相的第一工具。

javap Hello                        # 打印类的 public 成员签名
javap -p Hello                     # 打印所有成员(含 private)
javap -c Hello                     # 打印字节码指令(重点学习)
javap -c -l -v Hello               # -l 行号表+局部变量表,-v 完整附加信息
javap -c java.lang.String          # 反汇编 JDK 自带的类

实战示例:看 i++ 和 ++i 到底差在哪

public class Incr {
    public static void main(String[] args) {
        int a = 0;
        int b = a++;
        int c = ++a;
    }
}
javac Incr.java && javap -c Incr

输出(节选):

Code:
  stack=1, locals=4, args_size=1
     0: iconst_0           # 把 0 压栈
     1: istore_1           # 弹出存到 a  → a=0
     2: iload_1            # a 的值(0) 压栈
     3: iinc 1, 1          # a 自增 1   → a=1
     6: istore_2           # 弹出 0 给 b → b=0
     7: iinc 1, 1          # a 自增 1   → a=2
    10: iload_1            # a 的值(2) 压栈
    11: istore_3           # 弹出给 c   → c=2
    12: return

结论:b=a++ 是"先取原值,再自增";c=++a 是"先自增,再取新值"。字节码层看得一清二楚,不用死记。

javap 能解决的常见问题
- 自动装箱/拆箱发生在哪里
- 字符串拼接是用 StringBuilder 还是 invokedynamic
- 泛型桥接方法是否存在
- for-each 循环编译后是 iterator 还是数组遍历
- try-with-resources 展开成了什么样
- lambda 表达式编译成了什么(invokedynamic + 内部类)

3.2 jar:打包/解包 JAR 文件

功能:JAR 本质是 ZIP 格式,jar 命令用来创建、查看、解压 JAR 文件。

# 创建 JAR
jar cf app.jar -C out .            # 把 out 目录下所有文件打包成 app.jar
jar cfe app.jar com.example.Main -C out .  # 可执行 JAR:指定 Main-Class 入口
jar cmf MANIFEST.MF app.jar -C out .  # 自定义 MANIFEST.MF

# 查看 JAR
jar tf app.jar                     # 列出 JAR 内所有文件
jar tvf app.jar                    # 带大小/日期/所有者的详细列表

# 解压 JAR
jar xf app.jar                     # 解压到当前目录
jar xf app.jar com/example/A.class # 只解压某个文件

# 更新 JAR
jar uf app.jar new.properties      # 往已有的 JAR 里加文件

可执行 JAR 的关键MANIFEST.MF 里必须有 Main-Class: com.example.Main,且最后要空一行。

3.3 jarsigner:JAR 签名与验证

功能:用私钥给 JAR 数字签名,接收方用公钥验签,确保 JAR 没有被篡改、来源可信。

# 签名(先用 keytool 生成密钥对)
jarsigner -keystore my.keystore app.jar myalias
jarsigner -sigalg SHA256withRSA -digestalg SHA-256 app.jar myalias

# 验签
jarsigner -verify app.jar
jarsigner -verify -verbose -certs app.jar  # 详细验证+证书链展示

应用场景:Java Web Start(JNLP)、Applet(已废弃)、需要来源可信的分发场景。

3.4 jdeps:类与 JAR 依赖分析

功能:静态分析 class/JAR 的依赖关系,找出依赖了哪些包、哪些 JDK 内部 API(升级 JDK 必备)。

# 分析单个 JAR 的依赖
jdeps app.jar
jdeps -v app.jar                  # 详细输出(类级别的依赖)

# 分析依赖的 JDK 模块(JDK 9+ 模块化)
jdeps --list-deps app.jar         # 列出依赖了哪些 JDK 模块(java.base 等)
jdeps --print-module-deps app.jar # 只输出模块名,可直接喂给 jlink

# 找 JDK 内部 API 调用(JDK 8 升级 JDK 11/17 的第一道关)
jdeps --jdk-internals app.jar     # 标出 sun.misc.* 等内部 API
jdeps --internal-apionly app.jar  # 只看内部 API

# 递归分析依赖的 JAR
jdeps -cp 'lib/*' --recursive app.jar

典型场景:从 JDK 8 升级 JDK 17 时,先跑 jdeps --jdk-internals app.jar,所有用了 sun.misc.BASE64Encoder 等内部 API 的类直接标出来,省得运行时抛异常。

3.5 jdeprscan:扫描废弃 API

功能:专门扫描 class/JAR 里调用了哪些 @Deprecated 的方法/类,包括 JDK 废弃的和自定义废弃的。

# 扫描废弃的 JDK API 调用
jdeprscan app.jar
jdeprscan --release 17 app.jar    # 按 JDK 17 的废弃列表来扫
jdeprscan --release 11 app.jar    # 按 JDK 11 的废弃列表
jdeprscan --verbose app.jar       # 详细:每个调用点的位置

和 jdeps 的区别:jdeps 关注"依赖了什么",jdeprscan 只关注"用了哪些被标记为 deprecated 的 API"。升级 JDK 前两个工具配合使用。

3.6 jmod:JMOD 模块化打包

功能:JDK 9 引入的模块化格式(.jmod),比 JAR 能装更多东西:本地代码(.so/.dll)、配置文件、命令、头文件等。

# 创建 jmod
jmod create --class-path classes --libs lib/ --cmds bin/ mymodule.jmod

# 查看 jmod 内容
jmod list mymodule.jmod

# 描述模块信息
jmod describe mymodule.jmod

# 提取 jmod 内容
jmod extract --dir out mymodule.jmod

# 计算哈希(放到 module-info.java 的 hashes 里,防篡改)
jmod hash --module-path mods --output hashes.txt mymodule.jmod

JDK 自带的模块就打包成 .jmod 放在 $JAVA_HOME/jmods/ 目录里。

3.7 jimage:JIMAGE 运行时镜像操作

功能:JDK 9+ 用 JIMAGE(.jimage)格式把 JDK 内置模块打包在 lib/modules 文件里,比 JAR 体积更小、加载更快。jimage 用来查看/提取它的内容。

# 列出 JIMAGE 里的资源
jimage list $JAVA_HOME/lib/modules

# 提取某个资源(比如 java/lang/String.class)
jimage extract --dir out $JAVA_HOME/lib/modules java/lang/String.class

# 查看 JIMAGE 的基本信息
jimage info $JAVA_HOME/lib/modules
jimage verify $JAVA_HOME/lib/modules     # 校验一致性

平时开发一般不用,排查 JDK 自身的类加载问题或做定制 JRE 时会用到。

3.8 jlink:裁剪 JDK,生成定制运行时(重要)

功能:JDK 9+ 的杀手锏工具。只把应用实际用到的 JDK 模块打包成一个最小 JRE,不再需要分发 200MB+ 的完整 JDK。

# 第一步:用 jdeps 拿到依赖的模块列表
jdeps --print-module-deps app.jar
# 输出:java.base,java.logging,java.xml

# 第二步:jlink 生成最小运行时
jlink --module-path $JAVA_HOME/jmods \
      --add-modules java.base,java.logging,java.xml \
      --output my-mini-jre \
      --compress 2 \
      --strip-debug \
      --no-header-files \
      --no-man-pages

# 第三步:发布时把 app.jar + my-mini-jre 一起打包即可
my-mini-jre/bin/java -jar app.jar

裁剪效果:完整 JDK ~300MB,最小 java.base JRE ~40MB,差异巨大。Docker 镜像瘦身的必备工具。

常用 jlink 优化参数

参数 作用
--compress 2 ZIP 级别压缩,压得更狠
--strip-debug 去掉调试符号
--strip-native-commands 去掉 jmap/jstack 等诊断命令(生产可不需要)
--no-header-files / --no-man-pages 去掉头文件和 man 手册
--vm=server/client/minimal 选择 JVM 模式(server 默认)

3.9 jpackage:打包成操作系统原生安装包

功能:JDK 14+ 正式加入。把 JAR + 定制 JRE 打包成 Windows .msi/.exe、macOS .dmg/.pkg、Linux .deb/.rpm,带桌面图标、开始菜单、卸载入口。

# Windows 打包成 exe 安装程序
jpackage --type exe \
         --name MyApp \
         --input lib/ \
         --main-jar app.jar \
         --main-class com.example.Main \
         --icon app.ico \
         --win-menu \
         --win-dir-chooser \
         --win-shortcut

# 不打包 JRE(假定目标机已有 JRE)
jpackage --type exe --name MyApp --input lib/ --main-jar app.jar --app-version 1.0

JDK 17 对 jpackage 做了大量修复和增强,是 Java 桌面应用分发的官方推荐方式。


四、JVM 监控与诊断工具(线上排障核心)

这 11 个工具是线上问题排查的"瑞士军刀",按使用频率排序。

4.1 jps:查看 Java 进程(必用第一步)

功能:列出当前机器所有正在运行的 Java 进程和它们的 PID。Windows 任务管理器 / Linux ps 看 Java 进程不如 jps 直接。

jps                    # 输出:PID + 主类名/JAR 名
jps -l                 # 输出:PID + 主类全名
jps -v                 # 输出:启动时传的 JVM 参数(看堆多大、用的什么 GC)
jps -m                 # 输出:传给 main 方法的参数
jps -lv                # 常用组合:PID + 主类全名 + JVM 参数

典型输出

12345 org.springframework.boot.loader.JarLauncher -Xmx2g -XX:+UseG1GC
23456 sun.tools.jps.Jps

做任何诊断前先跑 jps -lv,拿到目标进程 PID,后面所有工具都要传 PID。

4.2 jstat:JVM 运行时指标(高频快照)

功能:连续采样 JVM 的类加载、GC、JIT 编译等核心指标,是判断"内存有没有泄漏、GC 正常不正常"的第一工具。

# 最常用:GC 统计,每 1 秒采样一次,连续采 10 次
jstat -gc 12345 1000 10

# 输出字段解读(关键):
# S0C/S1C:   Survivor 0/1 容量 (KB)
# S0U/S1U:   Survivor 0/1 已用
# EC/EU:     Eden 容量/已用
# OC/OU:     Old 容量/已用
# MC/MU:     Metaspace 容量/已用
# YGC/YGCT:  Young GC 次数/总耗时
# FGC/FGCT:  Full GC 次数/总耗时
# GCT:       GC 总耗时

其他常用子选项

jstat -gcutil 12345 1000  # 用百分比显示(已用/容量%),一眼看 Eden、Old 占比
jstat -gccause 12345      # 比 gcutil 多两列:上一次 GC 的原因
jstat -class 12345        # 类加载/卸载统计
jstat -compiler 12345     # JIT 编译统计
jstat -printcompilation 12345  # 最近被 JIT 编译的方法

诊断用法
- 跑 jstat -gcutil 12345 5000 20,观察 OU(Old 已用)曲线。每次 Young GC 后 OU 不断上涨 → 怀疑内存泄漏
- FGCT(Full GC 总耗时)持续攀升 → 调 GC 参数或升级收集器
- YGC 每秒好几十次 → 新生代太小,调 -Xmn

4.3 jstack:线程快照 + 死锁检测

功能:dump 某 Java 进程中所有线程的调用栈,并自动检测死锁。

# dump 线程栈到控制台
jstack 12345

# 输出到文件
jstack 12345 > thread_dump.txt

# 强制 dump(进程卡住不响应时,-F)
jstack -F 12345

# 带锁信息(默认就有)
jstack -l 12345

看线程栈的三个关键动作

  1. 找死锁:文件末尾有 Found one Java-level deadlock: 段落,直接列出死锁的线程、各自持有什么锁、等什么锁
  2. 找 BLOCKED 线程:搜索 java.lang.Thread.State: BLOCKED,看它们卡在哪个 synchronized 代码块
  3. 找 CPU 高的线程:(Linux)先 top -H -p 12345 找到耗 CPU 的线程 TID → 转十六进制 → 在 jstack 输出里搜对应 nid=0x... 的线程,看它在跑什么方法

典型死锁输出节选

Found one Java-level deadlock:
=============================
"Thread-0":
  waiting to lock monitor 0x... (which is held by "Thread-1")
"Thread-1":
  waiting to lock monitor 0x... (which is held by "Thread-0")

Java stack information for the threads listed above:
===================================================
"Thread-0":
        at DeadLock$1.run(DeadLock.java:15)
        - locked <0x...> (a java.lang.Object)   --> 持有锁 A
        - waiting to lock <0x...> (a java.lang.Object) --> 等锁 B

4.4 jmap:堆内存快照(OOM 排查核心)

功能:查看堆信息、生成堆转储文件(heap dump)。

# 查看堆总体信息(各代容量、使用量、GC 收集器)
jmap -heap 12345

# 查看各代对象统计(按类聚合数量和大小)
jmap -histo 12345                  # 所有对象
jmap -histo:live 12345             # 只统计活对象(会触发一次 Full GC)

# 生成堆转储文件(最常用!)
jmap -dump:format=b,file=heap.hprof 12345
jmap -dump:live,format=b,file=heap_live.hprof 12345  # 只 dump 活对象,文件更小

heap dump 怎么分析
- 用 JDK 自带的 jvisualvm(JDK 8 有,JDK 9+ 需要单独装 VisualVM)
- 用 Eclipse MAT(Memory Analyzer Tool)——行业标准,自动出泄漏嫌疑报告
- 用 JDK 自带的 jhat(已废弃,不推荐),或在线工具:HeapHero

heap dump 文件 = 当时堆的完整快照——里面所有对象、引用关系、GC Roots 全在。内存泄漏 90% 的真相都在里面。

4.5 jinfo:查看/修改 JVM 参数

功能:查看 JVM 进程的系统属性和 JVM 标志位,并且可以运行时动态修改部分可管理标志(不用重启进程)。

# 查看所有系统属性(=System.getProperties() 的内容)
jinfo -sysprops 12345

# 查看所有 JVM 标志位
jinfo -flags 12345

# 查看单个标志位的值
jinfo -flag PrintGC 12345

# 运行时开关某个标志位(不用重启)
jinfo -flag +PrintGC 12345         # 开启 GC 日志
jinfo -flag -PrintGC 12345         # 关闭 GC 日志
jinfo -flag MaxHeapFreeRatio=70 12345  # 修改数值型参数(不是所有都能改)

# 把所有信息(属性+标志+命令行)汇总输出
jinfo 12345

哪些标志可以动态改?看 java -XX:+PrintFlagsFinal -version | grep manageable,标了 manageable 的才可以运行时改。

4.6 jcmd:瑞士军刀(统一命令)

功能:JDK 7u4 引入,统一替代 jps/jstack/jmap/jinfo 等大部分功能。语法统一,功能更强。

# 列出所有 Java 进程
jcmd

# 帮助:看某个进程支持哪些诊断命令
jcmd 12345 help

# 线程栈(= jstack)
jcmd 12345 Thread.print
jcmd 12345 Thread.print -l=true    # 带锁信息

# 堆信息(= jmap -heap)
jcmd 12345 GC.heap_info

# 生成 heap dump(= jmap -dump)
jcmd 12345 GC.heap_dump heap.hprof
jcmd 12345 GC.heap_dump -all heap.hprof  # 包含不可达对象

# 触发 GC
jcmd 12345 GC.run
jcmd 12345 GC.run_finalization

# 对象统计(= jmap -histo)
jcmd 12345 GC.class_histogram
jcmd 12345 GC.class_histogram -all=true

# 查看 JVM 标志(= jinfo)
jcmd 12345 VM.flags
jcmd 12345 VM.flags -all              # 所有标志

# 查看系统属性
jcmd 12345 VM.system_properties

# JIT 编译统计
jcmd 12345 Compiler.codecache
jcmd 12345 Compiler.queue

# 动态开启/关闭 JFR(JDK Flight Recorder)
jcmd 12345 JFR.start name=myrec duration=60s filename=rec.jfr
jcmd 12345 JFR.check
jcmd 12345 JFR.stop name=myrec

趋势:官方推荐优先用 jcmd,jps/jstack/jmap/jinfo 这些单功能工具未来可能被淘汰。新环境上手直接 jcmd 即可。

4.7 jconsole:GUI 监控控制台

功能:JMX 图形化监控工具,实时看堆内存、线程、类加载、CPU 使用率、MBean 操作。

jconsole 12345                      # 直接连本地 PID
jconsole host:port                  # 连远程主机(需开启 JMX 远程端口)
jconsole localhost:1099

打开后六个标签页:
- 概览:堆内存、线程、类、CPU 四张图联动
- 内存:各代(Eden/Survivor/Old/Metaspace)的占用曲线,可手动执行 GC
- 线程:线程列表、每个线程的栈、死锁检测按钮(一键检测)
- :已加载/卸载类的数量
- VM 摘要:JVM 参数、系统属性、JDK 版本汇总
- MBean:所有注册的 MBean,可以调用方法、读写属性(比如手动触发 GC、修改日志级别)

远程开启 JMX(生产要加鉴权+SSL)

java \
  -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=1099 \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Djava.rmi.server.hostname=192.168.1.100 \
  -jar app.jar

4.8 jfr:JDK Flight Recorder(生产级事件追踪)

功能:JDK 11 开源(Oracle JDK 7 就有但商业收费)。JVM 内建的超低开销事件采集系统,能记录几千种事件(GC、锁、线程、IO、异常、JIT 等),性能开销 <1%,生产环境可以常年开着。

# 方式一:启动时就开启 JFR
java -XX:StartFlightRecording:filename=rec.jfr,duration=1h -jar app.jar

# 方式二:运行时用 jcmd 开启
jcmd 12345 JFR.start name=myrec maxsize=500m maxage=24h
jcmd 12345 JFR.check
jcmd 12345 JFR.dump name=myrec filename=rec.jfr
jcmd 12345 JFR.stop name=myrec

# 方式三:jfr 工具(JDK 19+)
jfr start --pid 12345 --name myrec
jfr dump --name myrec --output rec.jfr
jfr summary rec.jfr          # 打印事件摘要
jfr print rec.jfr            # 打印全部事件(慎用,量大)
jfr print --events GC rec.jfr  # 只看 GC 事件

JFR 文件怎么分析
- 用 JDK Mission Control(JMC)——图形化分析器,火焰图、GC 详情、热点方法、锁竞争、异常统计全在里面
- JMC 需要单独下载(不再随 JDK 发布)

JFR + JMC 是目前 Java 生产诊断的黄金组合,比 Arthas/BTrace 更轻量、更全面,且 Oracle 官方出品。

4.9 jhsdb:HotSpot Serviceability Agent(深度调试)

功能:JDK 9+ 替代了旧的 jsadebugd,可以挂到运行中的 JVM 进程或核心转储(core dump),检查 JVM 内部状态(对象、栈、CodeCache、元空间)。

# 启动 GUI(类似旧的 HSDB)
jhsdb hsdb --pid 12345

# CLI 模式:连接进程/核心转储执行特定命令
jhsdb clhsdb --pid 12345
jhsdb clhsdb --exe java --core core.12345

# 常用子命令(连接后):
jhsdb jmap --pid 12345 --heap           # 等于 jmap -heap
jhsdb jmap --pid 12345 --histo          # 等于 jmap -histo
jhsdb jstack --pid 12345                # 等于 jstack
jhsdb jinfo --pid 12345                 # 等于 jinfo

平时用 jcmd/jmap/jstack 够了,jhsdb 是 JVM 工程师或极端疑难杂症场景(比如 core dump 分析)才会用的重型工具。

4.10 jstatd:远程 jstat 守护进程

功能:在远端机器上启动一个 RMI 守护,本地 jvisualvm / jstat 可以远程监控。

# 简单启动(无安全策略,仅限内网)
jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.1.100

jstatd.all.policy 内容:

grant codebase "file:${java.home}/../lib/tools.jar" {
    permission java.security.AllPermission;
};

生产环境不建议用(不安全),改 SSH 隧道 + 本地 jcmd 更稳妥。


五、安全与证书工具

5.1 keytool:密钥与证书管理(高频实用)

功能:JDK 自带的密钥库(keystore)和证书管理工具,用于 HTTPS、数字签名、JWT RSA 密钥对等场景。

# ===== 一、创建密钥 =====

# 生成 RSA 密钥对(2048 位),存进 JKS 密钥库
keytool -genkeypair \
  -alias myserver \
  -keyalg RSA -keysize 2048 \
  -validity 3650 \
  -keystore server.keystore \
  -storepass changeit \
  -dname "CN=localhost,OU=Dev,O=MyOrg,L=BJ,ST=BJ,C=CN"

# 生成证书签名请求(CSR),发给 CA 机构签名
keytool -certreq \
  -alias myserver \
  -file myserver.csr \
  -keystore server.keystore

# 导入 CA 返回的证书
keytool -importcert -alias myserver -file myserver.crt -keystore server.keystore

# ===== 二、查看密钥库内容 =====
keytool -list -keystore server.keystore
keytool -list -v -keystore server.keystore -alias myserver   # 看具体条目详情
keytool -list -rfc -keystore server.keystore                  # 以 RFC(PEM)格式输出

# ===== 三、JDK 信任库 =====
# JDK 自带的 CA 证书存放在:
# $JAVA_HOME/lib/security/cacerts(JDK 9+,旧版在 jre/lib/security/cacerts)
# 默认密码:changeit

# 查看 JDK 信任了哪些 CA 证书
keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit | wc -l

# 导入企业自签证书到 JDK 信任库(解决 HTTPS PKIX path building failed 错误)
keytool -importcert \
  -alias corp-ca \
  -file corp-ca.crt \
  -keystore $JAVA_HOME/lib/security/cacerts \
  -storepass changeit \
  -noprompt

# 删除 JDK 信任库里的某个别名
keytool -delete -alias corp-ca -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit

# ===== 四、导出 =====
# 导出某个别名的证书(公钥)给对方
keytool -exportcert -alias myserver -file myserver.crt -keystore server.keystore

# 导出 PKCS12 格式(跨平台、兼容 OpenSSL),给 nginx/Apache 用
keytool -importkeystore \
  -srckeystore server.keystore -srcstoretype JKS \
  -destkeystore server.p12 -deststoretype PKCS12

两种常见密钥库格式

格式 扩展名 说明
JKS .jks / .keystore Java 原生格式,历史悠久,安全性较弱(仅密码保护)
PKCS12 .p12 / .pfx 行业标准,加密强度高,跨语言兼容,JDK 9+ 已经是默认格式

新建密钥库时建议直接用 PKCS12:keytool -genkeypair -storetype PKCS12 ...

5.2 kinit / klist / ktab:Kerberos 认证三件套

功能:和 Hadoop、Kafka、企业 AD/LDAP 的 Kerberos SSO 认证交互。

# kinit:获取 TGT 票据(输入密码或用 keytab)
kinit admin@CORP.COM
kinit -kt admin.keytab admin@CORP.COM     # 用 keytab 免密登录

# klist:查看当前缓存的票据
klist
klist -e                                   # 看加密类型

# ktab:管理 keytab 文件(存密钥,免密登录用)
ktab -k admin.keytab -a admin@CORP.COM     # 往 keytab 加条目
ktab -k admin.keytab -l                    # 列出 keytab 条目
ktab -k admin.keytab -d admin@CORP.COM     # 删除条目

做大数据生态、接入企业 SSO 才会用到,普通 Java 开发者接触较少。


六、文档与开发辅助工具

6.1 javadoc:生成 API 文档

功能:从源码注释里的 /** ... */ Javadoc 标签,生成静态 HTML API 文档。

# 生成整个项目的文档
javadoc -d docs -sourcepath src -subpackages com.example

# 带更多选项
javadoc -d docs \
  -sourcepath src \
  -subpackages com.example \
  -classpath lib/* \
  -encoding UTF-8 \
  -charset UTF-8 \
  -docencoding UTF-8 \
  -windowtitle "My Project API" \
  -doctitle "My Project API Documentation" \
  -author -version \
  -link https://docs.oracle.com/en/java/javase/17/docs/api/  # 链接到 JDK 文档

常用 Javadoc 标签:

标签 作用
@param 方法参数说明
@return 返回值说明
@throws / @exception 抛出的异常
@author 作者(-author 参数才会显示)
@version 版本(-version 参数才会显示)
@see / {@link} 引用其他类/方法
@since 从哪个版本开始加入
@deprecated 废弃说明

6.2 jdb:命令行调试器

功能:JDK 自带的命令行 Java 调试器,类似 gdb/C++。没有 IDE 时的紧急调试手段。

# 启动被调试程序,开启 JDWP 调试端口
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 -jar app.jar

# 另开窗口,jdb 连接上去
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=5005

# 调试命令(和 gdb 风格类似)
stop in com.example.Main.main        # 在方法入口打断点
stop at com.example.Main:20          # 在第 20 行打断点
run                                  # 启动执行
cont                                 # 继续运行
step                                 # 单步进入(进入方法内部)
next                                 # 单步跳过(不进入方法)
where                                # 打印当前线程栈
print varName                        # 打印变量值
locals                               # 打印当前所有局部变量
dump objName                         # 打印对象的所有字段
threads                              # 列出所有线程
thread 0x123                         # 切换到某个线程
clear com.example.Main:20            # 清除断点
exit                                 # 退出

现代开发基本都用 IDE 的调试器,jdb 是 Linux 无头环境紧急排错的兜底。

6.3 jshell:Java 交互式 REPL(JDK 9+)

功能:Java 的命令行交互式解释器,随手验证一段代码、试一个 API,不用写完整类、不用编译。

jshell

进入后的使用:

jshell> int a = 1 + 2
a ==> 3

jshell> System.out.println("Hello JShell")
Hello JShell

jshell> List<String> list = List.of("a", "b", "c")
list ==> [a, b, c]

jshell> list.stream().map(String::toUpperCase).toList()
$4 ==> [A, B, C]

jshell> /imports            # 看已导入的包
jshell> /vars               # 看定义的变量
jshell> /methods            # 看定义的方法
jshell> /edit               # 用外部编辑器打开当前会话代码
jshell> /save session.jsh   # 保存会话到文件
jshell> /open session.jsh   # 恢复保存的会话
jshell> /reset              # 清空所有定义
jshell> /exit               # 退出

非常适合:验证 Stream API、正则表达式、日期格式、数值转换这类一两行就能跑的小逻辑。

6.4 jrunscript:命令行脚本运行

功能:JDK 自带的脚本运行器,默认 JavaScript(Nashorn,JDK 11 后已被移除/废弃),但可以通过 -l 指定其他 JSR-223 兼容的脚本语言。

# 运行一段 JS(JDK 8 才有 Nashorn)
jrunscript -e "print('Hello')"
jrunscript script.js

# 列出可用的脚本引擎
jrunscript -q

JDK 17 里 Nashorn 已经移除,这个工具的实用价值下降。替代方案:直接用 Java 写 main 方法或 Groovy。


七、RMI 与序列化辅助

7.1 rmiregistry:RMI 注册表

功能:启动 RMI 命名服务的注册中心,服务端把远程对象 bind 上去,客户端通过名字 lookup 拿远程对象。

# 在端口 1099 启动(默认端口)
rmiregistry

# 指定其他端口
rmiregistry 2099

RMI(Remote Method Invocation)是 Java 原生的远程调用机制,Spring/Dubbo 生态普及后已经很少新用。遗留系统维护可能会碰到。

7.2 serialver:生成 serialVersionUID

功能:计算类的 serialVersionUID(序列化版本 UID)。

// 业务代码里经常这样写:
private static final long serialVersionUID = 1L;

但 1L 只是随便写的。真正的 UID 是根据类名、字段、方法签名等综合计算出来的哈希值。

serialver com.example.User              # 输出计算出的 UID
serialver -classpath out com.example.User

# 示例输出:com.example.User:    private static final long serialVersionUID = 6803793133171234567L;

直接把输出复制粘贴进代码,就是标准的 UID。比手动写 1L 更严谨(类结构变了 UID 会变,反序列化版本不一致直接报错,不会默默出错)。


八、辅助工具

工具 功能
jabswitch Java Access Bridge:把 Java GUI 接入 Windows 无障碍 API,屏幕阅读器读 Swing 控件
jaccessinspector 无障碍检查器:查看 Java GUI 组件的可访问性信息
jaccesswalker 无障碍遍历器:层级浏览组件树,检查无障碍属性

这三个是 Java Accessibility 套件,纯辅助工具,和开发/运维几乎无关。


九、学习路径建议

阶段 重点掌握的工具 标准
第一阶段:开发日常 javac、java、javadoc、jar、javap 编译、打包、调试、看字节码不卡壳
第二阶段:问题排查 jps、jstat、jstack、jmap、jconsole 能独立排查 CPU 高、死锁、OOM、内存泄漏
第三阶段:进阶诊断 jcmd、jinfo、jfr、jpackage、jlink 能用 jcmd 统一操作、JFR 录制生产事件、裁剪 JRE 分发包
第四阶段:极端场景 jhsdb、jdeps、jdeprscan、keytool 能分析 core dump、升级 JDK 扫描兼容性、处理证书链问题

十、速查索引

目标 用什么工具
编译 Java 源码 javac
启动 Java 程序 java(控制台)/ javaw(无控制台)
打包解包 JAR jar
看字节码指令 javap -c
分析类/JAR 依赖 jdeps
找废弃 API 调用 jdeprscan
找 JDK 内部 API 调用 jdeps --jdk-internals
升级 JDK 前兼容性扫描 jdeps + jdeprscan
裁剪 JRE jdeps --print-module-deps + jlink
打包成 exe/msi 安装包 jpackage
找 Java 进程 PID jps / jcmd
看 GC/内存实时数据 jstat -gcutil 1000
线程栈 + 死锁检测 jstack / jcmd Thread.print
堆 dump jmap -dump / jcmd GC.heap_dump
看堆各代使用量 jmap -heap / jcmd GC.heap_info
对象实例数排名 jmap -histo:live / jcmd GC.class_histogram
动态开关 GC 日志 jinfo -flag +PrintGC
统一诊断命令 jcmd
GUI 监控 jconsole / JMC(单独下载)
生产级低开销事件追踪 JFR(jcmd JFR.start + JMC 分析)
core dump 分析 jhsdb clhsdb
密钥库/证书管理 keytool
Kerberos 认证 kinit / klist / ktab
生成 API 文档 javadoc
命令行调试器 jdb
交互式 Java jshell
serialVersionUID 计算 serialver

十一、总结

JDK 的 bin 目录不是"编译器和 java 命令所在的文件夹",而是 Java 生态的一整套工具箱。

开发阶段:javac 编译、jar 打包、javadoc 生成文档、javap 看字节码查语法糖、jshell 快速验证小片段。

运行阶段:jps 找进程 → jstat 看 GC → jstack 看线程 → jmap 抓堆 → jcmd 做统一操作 → jconsole/JFR 做持续监控。按这个套路,线上 90% 的问题能定位。

分发阶段:jdeps 看依赖 → jlink 剪 JRE → jpackage 打 exe/msi,一套完成。

安全阶段:keytool 管密钥和证书、解决 HTTPS 自签证书报错。

一句话记忆:编译运行看 javac/java,线上排障走 jps-jstat-jstack-jmap-jcmd,分发打包 jlink+jpackage,证书密钥找 keytool。