JShell 与 JPackage 交互环境
用 jshell 即时验证语法与 API,用 jpackage 打出平台原生安装包。
0. 本节阅读指引(先读这一节)
本篇是「JShell 与 JPackage」交互环境与打包指南。
零基础第一遍只读:概念引入、jshell 完整会话示例、jpackage 完整流程;会用 jshell 验证语法、会打最简单的安装包。
可跳过:jpackage 平台选项、应用配置与 jshell 设置遇到再查。
前置:001 Java 概述与开发环境。
概念引入:两个工具各管一头
- jshell(JDK 9+)是 REPL(Read-Eval-Print Loop,读取-求值-打印循环):输入一行 Java 代码,立刻看到结果,不用建工程、不用写
main、不用编译。类比:Python 的交互式解释器,或”带即时反馈的草稿纸”。学新 API、验证正则、算个日期,都比”建测试类跑一遍”快得多。 - jpackage(JDK 14+)是打包器:把”JRE + 你的 jar + 启动器”打成一个平台原生安装包(Windows 的 msi/exe、macOS 的 dmg、Linux 的 deb/rpm),让没装 Java 的用户也能双击安装。类比:把”程序 + 精简行李箱(自带运行时)“打包成一件托运行李。
两者的共同主题是”降低门槛”:jshell 降低学习与验证的门槛,jpackage 降低交付与安装的门槛。顺带一提,JDK 25 转正的”紧凑源文件与实例 main”(JEP 512)让单文件脚本进一步简化,与 jshell 形成”草稿纸 + 纸上程序”的互补。
jshell 完整会话(照着敲一遍)
$ jshell
| Welcome to JShell -- Version 25
| For an introduction type: /help intro
jshell> 1 + 1
$1 ==> 2 // 表达式结果自动存进变量 $1
jshell> String name = "Java"
name ==> "Java"
jshell> name.length()
$3 ==> 4 // 方法返回值也有编号
jshell> import java.time.LocalDate // import 即输即生效
jshell> LocalDate.now().plusDays(7)
$5 ==> 2026-09-15 // 自带 toString,日期直接看结果
jshell> int square(int x) { return x * x; } // 方法定义无需类包装
| Created method square(int)
jshell> square(9)
$7 ==> 81
jshell> /vars // 查看所有变量
| String name = "Java"
jshell> /exit
| Goodbye
典型工作流:开了两个终端——左边 jshell 试 API 写法,右边把验证过的代码抄进工程;遇到”这个正则到底匹配啥”的问题,十秒钟出答案。
jpackage 完整流程(从 jar 到安装包)
# 0) 前提:已经用 Maven/Gradle 打出 app.jar(见 076 构建工具)
# 1) (可选)用 jlink 定制一个只含所需模块的精简 JRE,
# 让安装包不带完整运行时,体积从 ~300MB 缩到几十 MB
jlink --add-modules java.base,java.logging,java.sql \
--output myjre --strip-debug --no-header-files --no-man-pages
# 2) 打 Windows 安装包(需已安装 WiX Toolset 3.x)
jpackage --name MyApp \
--input target \
--main-jar app.jar \
--main-class com.example.Main \
--app-version 1.0.0 \
--vendor "Acme Inc" \
--runtime-image myjre \
--win-shortcut --win-menu
# 3) 产物:target/dist 下的 MyApp-1.0.0.msi,双击安装即用
macOS 与 Linux 换 --type dmg / --type deb(或 rpm),其余参数一致;--main-jar 与 --module 二选一(模块化应用用后者)。
常见陷阱
jshell 陷阱一:把会话状态当一次性。 变量、方法会跨片段累积,改了类定义后旧变量仍是旧类型;怀疑状态污染就 /reset 重来。
jshell 陷阱二:不带分号在多行表达式中报错。 单行表达式可省分号,跨行写复杂语句时补全分号最稳妥。
jshell 陷阱三:想用第三方 jar 却没挂 classpath。 启动时 jshell --class-path "lib/*",之后 import 即可;启动后才发现,得退出重启。
jpackage 陷阱四:Windows 上报 “WiX tools (msi/exe) not found”。 打 msi/exe 必须先装 WiX Toolset 3.x 并加入 PATH;不想装就用 --type app-image 产出一个绿色文件夹。
jpackage 陷阱五:以为它会自动编 jar。 它只做”打包”,--input 目录里必须已经有构建产物;先把 Maven/Gradle 流程跑通。
jpackage 陷阱六:图标与签名。 --icon 各平台要求各自的图标格式(ico/icns/png);正式分发还要处理代码签名,这一步在 CI 里做而不是本地。
jshell 启动
基本写法:进入交互
jshell
# 启动 REPL 交互环境
jshell
基本写法:指定版本进入
jshell --execution <模式>
# 本地执行模式
jshell --execution local
基本写法:执行片段
jshell -e "<代码>"
# 直接执行单段代码
jshell -e "System.out.println(\"hi\");"
jshell 会话控制
基本写法:加载文件
/open <文件路径>
// 在 jshell 内加载脚本文件
/open snippet.java
基本写法:保存片段
/save <文件路径>
// 保存当前会话片段到文件
/save session.java
基本写法:列出片段
/list
// 列出已输入的代码片段(带编号)
/list
// 仅列出有效片段
/list -all
基本写法:查看变量
/vars
// 列出已定义的变量及值
/vars
基本写法:查看方法
/methods
// 列出已定义的方法
/methods
基本写法:查看类型
/types
// 列出已定义的类与接口
/types
基本写法:查看导入
/imports
// 列出已导入的包
/imports
基本写法:编辑片段
/edit <片段编号>
// 用外部编辑器编辑片段
/edit 1
基本写法:重置会话
/reset
// 清空所有片段,重新开始
/reset
基本写法:退出
/exit
// 退出 jshell
/exit
jshell 设置
基本写法:设置反馈模式
/set feedback <模式>
// concise / normal / silent / verbose
/set feedback verbose
基本写法:添加导入
import <包名>;
// 直接输入 import 语句即可
import java.util.stream.*;
基本写法:设置类路径
jshell --class-path <路径>
# 启动时指定类路径
jshell --class-path "lib/*;bin"
jpackage 基础
基本写法:构建 Windows 安装包
jpackage --name <名称> --input <输入> --main-jar <主jar>
# 打包成 Windows 安装程序(msi/exe)
jpackage --name MyApp --input target --main-jar app.jar
基本写法:指定主类
jpackage --name <名称> --module <模块>/<主类>
# 模块化应用打包
jpackage --name MyApp --module com.example.app/com.example.app.Main
基本写法:指定运行时镜像
jpackage --runtime-image <镜像目录>
# 使用自定义 JRE
jpackage --name MyApp --input target --main-jar app.jar --runtime-image myjre
基本写法:应用镜像(免装工具链的通用产物)
jpackage --type app-image
# 产出包含启动器的绿色目录,无需 WiX/系统打包器
jpackage --type app-image --name MyApp --input target --main-jar app.jar
jpackage 平台选项
基本写法:Windows 安装器类型
jpackage --win-msi
# 生成 MSI 安装包
jpackage --name MyApp --input target --main-jar app.jar --win-msi
基本写法:Windows 快捷方式
jpackage --win-shortcut --win-menu
# 创建桌面快捷方式与开始菜单项
jpackage --name MyApp --input target --main-jar app.jar --win-shortcut --win-menu
基本写法:macOS dmg
jpackage --type dmg --name <名称>
# 生成 macOS dmg 镜像
jpackage --type dmg --name MyApp --module com.example.app/com.example.app.Main
基本写法:macOS 应用图标
jpackage --icon <icns 文件>
# 指定应用图标
jpackage --name MyApp --input target --main-jar app.jar --icon icon.icns
基本写法:Linux deb/rpm
jpackage --type <deb|rpm>
# 生成 Linux 安装包
jpackage --type deb --name myapp --input target --main-jar app.jar
jpackage 应用配置
基本写法:设置版本与供应商
jpackage --app-version <版本> --vendor <供应商>
# 应用版本与供应商
jpackage --name MyApp --input target --main-jar app.jar \
--app-version 1.0.0 --vendor "Acme Inc"
基本写法:传入 JVM 参数
jpackage --java-options "<参数>"
# 启动时传入 JVM 参数
jpackage --name MyApp --input target --main-jar app.jar \
--java-options "-Xmx512m -Dfile.encoding=UTF-8"
基本写法:应用参数
jpackage --arguments "<参数>"
# 启动应用时传入的命令行参数
jpackage --name MyApp --input target --main-jar app.jar \
--arguments "--mode=prod"
基本写法:关联文件类型
jpackage --file-associations <属性文件>
# 关联文件扩展名
jpackage --name MyApp --input target --main-jar app.jar \
--file-associations app.properties
基本写法:添加资源
jpackage --resource-dir <目录>
# 指定图标与许可文件目录
jpackage --name MyApp --input target --main-jar app.jar \
--resource-dir res
基本写法:临时目录与详细输出
jpackage --temp <目录> --verbose
# 指定临时目录并输出详细信息
jpackage --name MyApp --input target --main-jar app.jar \
--temp build/tmp --verbose
小结
初学者记住三点:
- jshell 是 Java 草稿纸:表达式即输即得,
/vars、/reset、/exit三个命令最常用。- jpackage 打”自带 JRE 的安装包”;打 msi 前先装 WiX,怕麻烦先用
--type app-image。- 两者都不参与构建:jar 交给 Maven/Gradle,jpackage 只管封装交付。
进阶者还需注意:
- jlink + jpackage 组合能把交付体积压到几十 MB,模块清单用
jdeps --print-module-deps从代码反推。 - jshell 默认在每个语句间自动持久状态,教学演示建议
/set feedback concise减少噪音。 - JDK 25+ 的紧凑源文件与实例 main 让”单文件脚本”不用类包装即可运行(
java script.java),轻量脚本可不再依赖 jshell。