简介:面向64位Windows平台的JDK 7u5(jdk1.7.0_05)开发环境包,适合需要维护旧版Java项目、学习Java SE 7语法与API的开发者使用。包内提供JDK与JRE及编译、调试等开发工具,并带有demos示例,便于在64位系统上验证Java 7的字符串switch、try-with-resources、NIO.2文件系统API、钻石操作符与Fork/Join并行框架等特性,也能帮助理解早期Java 7环境与后续版本的差异。压缩包约15.69MB,文件总数显示为0、类型明细暂无,包内结构以平台展示为准,使用时可结合JDK安装目录与demos示例查看。已有272人学习或下载,适合作为旧项目兼容测试、教学演示和Java 7特性入门的参考环境;64位版本在内存利用与大型应用运行方面更具优势,但版本较早,建议仅在隔离环境或兼容性验证场景中使用。
1. 先认清 jdk-7u5-windows-x64-demos:64 位 JDK 7 的示例源码包,不含 java.exe
前阵子有人把一个 2012 年的压缩包丢过来,问能不能让里面的 SwingSet2 跑起来。文件名里的「64 位」说的是它配套的 JDK,很多人以为下完就能写 Java,解压后翻遍目录也找不到 java.exe——它本来就不含运行时,只有一堆示例源码和几个预编译 jar。这东西覆盖的范围很窄,但很具体:官方当年怎么写 Swing、怎么用 Graphics2D 画布、怎么组织 JNLP 描述文件,全在这几个目录里摊着,比任何二手教程都直接。适合三类人:要读 Java2D 绘制源码的、要复现一个老界面做对比的、要维护内网 Java Web Start 客户端的。动手前先确认你手里有 JDK 7u5 本体,不然每一步都会卡在找不到 javac 上。
2. 解压后先别急着编译:五个顶层目录对应五类需求
拿到包的第一反应通常是双击某个 jar,然后什么都没发生。真正常见的误区是把它当成一个整体工程——实际上这五个目录互不相干,源码布局、编译方式、入口类都不一样,先对上号再动手,能省掉大半的无效试错。我一般把它解压到D:\demos这种独立路径,而不是塞进 JDK 安装目录,原因在 2.3 里说。
2.1 目录速查:jfc、applets、jnlp 各装了什么
| 目录 | 里面是什么 | 能否直接跑 | 对应诉求 |
|---|---|---|---|
demo\jfc | Swing 与 Java2D 的完整示例:SwingSet2、Java2D、Notepad、Font2DTest、Metalworks、TableExample 等 | 多数带预编译 jar,java -jar可用 | 读 UI 源码、抄绘制套路 |
demo\applets | 二十多个经典 applet:动画、时钟、分形、排序可视化 | 需要appletviewer,浏览器已不支持 | 教学演示、历史代码参考 |
demo\jnlp | Java Web Start 的 jnlp 描述文件与配套示例 | 需要javaws | 维护老内网客户端 |
demo\plugin | 浏览器插件相关示例 | 现代浏览器基本无法复现 | 排查历史兼容问题 |
demo\scripting | jrunscript 的脚本示例,用 JS 直接调 Java API | 需要jrunscript | 做轻量脚本化验证 |
不同构建批次给出的 demos 包目录会略有出入,以你手上解压出来的结果为准;上表是我这包的实际结构,五个主干目录之外没有别的东西。表格里「能否直接跑」这一列是保守估计——jfc下的示例绝大多数都配了 jar,但 jar 的 Class-Path 清单未必写全,所以「能跑」和「跑对」是两回事,第 3 章会逐个拆。
2.2 三类人只需要三块,别整包编译
如果你的目标是读绘制代码,直接进demo\jfc\Java2D,那里的Java2Demo包是官方写得最完整的一套 Graphics2D 教学代码,从抗锯齿、渐变填充到双缓冲都有独立页签,每个页签一个源文件,改一个参数立刻能看到画面变化,比读文档快得多。要复现界面做对比,进demo\jfc\SwingSet2,它是 JDK 7 时代 LAF(外观)能力的全集展示,切一次 Metal / Nimbus / Windows 就能看出当年 Swing 的边界在哪。要查 JNLP 的写法,进demo\jnlp\samples看 jnlp 里的 codebase、jar 资源声明和main-class属性怎么配合。
反过来说,demo\applets和demo\plugin这两块,今天的实际用途基本只剩「考古」——浏览器侧的插件早已不能用了,剩下的入口只有appletviewer。所以别一上手就对整个demo目录跑全量编译,那会引出几百条和你无关的报错,先锁定一个目录。
2.3 前置条件:JAVA_HOME 必须指向 JDK,不是 JRE
demos 包本身不带编译器,编译源码得靠外部的 JDK。这里有个很容易踩的点:机器上装了 JDK,但JAVA_HOME指向的是同版本的 JRE,java -version一切正常,javac却找不到。我习惯每次开新窗口先这样确认一遍,只影响当前会话,不动系统环境变量:
:: 只对当前 cmd 窗口生效,避免污染系统环境变量 set JAVA_HOME=C:\Java\jdk1.7.0_05 set PATH=%JAVA_HOME%\bin;%PATH% :: 两个都要有输出,缺一个就是路径指错了 java -version javac -version :: 显式检查 javac 是否存在,比事后报错好排查 if not exist "%JAVA_HOME%\bin\javac.exe" echo JAVA_HOME 指向的不是 JDKjava -version的输出里重点看最后一行是不是64-Bit Server VM,这一行决定了后面跑大堆示例时会不会直接OutOfMemoryError。set PATH=%JAVA_HOME%\bin;%PATH%里的分号是 Windows 的路径分隔符,把它放在最前面是有意的:机器上如果同时装了 JDK 8 或更高版本,后写的会覆盖前面的,不前置就会莫名跑成别的版本。
至于为什么建议解压到独立路径而不是 JDK 安装目录:官方说法是放进 JDK 根目录后demo和bin同级,相对路径短。但只要你有升级或重装 JDK 的打算,那个目录就会被整个覆盖掉,辛苦改过的示例源码一起没。独立路径加显式JAVA_HOME,是更稳的组合。
3. 跑通三个入口:SwingSet2、Java2D Demo 与 jrunscript 的实际命令
这一章的命令都可以直接复制。三个入口分别对应三种典型的工程形态:纯 jar 启动、带包名主类的 jar、以及从源码编译。把它们走通,剩下的示例基本是同一套模式的排列组合。
3.1 SwingSet2:少了 swinglafs.jar 就会退回默认外观
cd /d D:\demos\demo\jfc\SwingSet2 "%JAVA_HOME%\bin\java" -cp "SwingSet2.jar;swinglafs.jar" SwingSet2-cp里两个 jar 用分号分隔,这是 Windows 与 Linux 的第一处差异,照抄网上 Linux 教程里的冒号会直接报Could not find or load main class。主类写SwingSet2,没有包名前缀,这一点从 jar 里 class 文件的路径就能看出来。
swinglafs.jar是第二个 jar 的作用所在:SwingSet2 支持在运行时切换多种外观,其中 Nimbus 等非核心 LAF 被打包在这个附属 jar 里。只写java -jar SwingSet2.jar时,jar 清单里的 Class-Path 不一定把swinglafs.jar带上,切换外观会抛ClassNotFoundException,或者干脆静默回落到 Metal——界面能开,但你会以为「原来就长这样」。这类「不报错但结果不对」的情况,比崩掉更难查。
3.2 Java2D Demo:主类带包名,资源不在 classpath 上就画不出东西
cd /d D:\demos\demo\jfc\Java2D "%JAVA_HOME%\bin\java" -cp "Java2Demo.jar" Java2Demo.Java2Demo主类是Java2Demo.Java2Demo,带完整包名。这是最常写错的一处,java -cp Java2Demo.jar Java2Demo会报找不到主类。判断规则很简单:用jar tf看一眼 class 文件的路径前缀,前缀是什么,主类就写什么。
第二个坑在资源。这套示例的图片、字体、属性文件都打在 jar 内部,用-cp Java2Demo.jar启动一切正常。但如果你改成「把编译输出的 classes 目录丢进 classpath」这种调试用法,就必须同时把源码里的 resources 目录一起加进去,否则窗口能弹出来,画布区域却是空白或灰底——程序不崩,只是没内容。我排查这类问题一般先看资源加载那行的返回值,而不是盯着绘制代码。
3.3 从源码编译:用 @argfile 对付不统一的源码布局
demos 的源码布局并不统一:有的把包结构摊在src下,有的直接一堆.java放在目录根,逐个写文件名不现实。稳妥做法是先收集文件列表,再交给 javac:
cd /d D:\demos\demo\jfc\Notepad :: 把所有 java 源文件路径写进一个文本,避免命令行过长 dir /s /b src\*.java > sources.txt :: -encoding 按源码实际编码填,老示例多为 GBK "%JAVA_HOME%\bin\javac" -encoding GBK -d D:\build\notepad -sourcepath src @sources.txt :: 运行:把输出目录和资源目录都放进 classpath "%JAVA_HOME%\bin\java" -cp "D:\build\notepad;src" 主类名四个参数各管一件事,不能混着理解。-encoding GBK是告诉编译器「按什么编码读源文件」,它跟运行时 JVM 的默认字符集是两码事,第 4 章会展开。-d D:\build\notepad指定 class 输出目录,不加的话.class会和源码混在一棵树上,改一次错一次。-sourcepath src让编译器在需要时自己去找依赖的源文件,省掉手动列依赖的顺序问题。@sources.txt是 javac 的参数文件语法,把一长串路径从命令行挪进文件里。
-cp里那个;src很容易被忽略:图标、属性文件这类非 class 资源不参与编译,不会被复制到输出目录,必须让运行时的 classpath 也能看到它们。主类名同样用jar tf反查,或者直接看原目录里 jar 的清单,比自己猜包名可靠。
3.4 jrunscript 与 javaws:两个几乎被忘掉的入口
demo\scripting下的示例用的是 JDK 7 自带的脚本引擎,命令行入口是jrunscript。不想翻文件的话,一行就能验证引擎是否可用:
"%JAVA_HOME%\bin\jrunscript" -e "print(java.lang.System.getProperty('java.version'))"-e后面直接跟脚本片段,print是脚本侧的输出函数,java.lang.System这种全限定名可以直接引用 Java 类——这就是当年「脚本调 Java」的最小闭环,写自动化小工具时很省事。
JNLP 那边要先找到 jnlp 文件,再交给javaws:
cd /d D:\demos\demo\jnlp\samples dir /s /b *.jnlp "%JAVA_HOME%\bin\javaws" 某个示例.jnlp关键在于工作目录:jnlp 里的codebase如果写的是相对路径,javaws会相对当前目录去解析 jar,目录不对就报找不到资源。所以先cd到 jnlp 所在目录再启动,是成本最低的规避方式。
4. 参数与兼容性:64 位、编码、外观三处最容易拧错的地方
4.1 「64 位」到底约束了什么
先把一个常见误解说清:这个包里的示例绝大部分是纯 Java 代码,不含本地库,用 32 位 JDK 跑也能跑起来。文件名里的windows-x64真正约束的是它配套的 JDK 本体——当年官方把 32 位和 64 位的 demos 分开打包,是为了跟同批发布的安装包对齐,不是因为代码里有什么 64 位专属指令。
所以真正的边界在内存和路径上。64 位 JVM 能给出更大的堆,跑那些一次性加载大量图片的 Java2D 示例时不容易 OOM;而 32 位 JVM 在默认堆下跑同样示例,可能在中途抛OutOfMemoryError: Java heap space,这时加大-Xmx也没用——32 位进程的地址空间本身就有限。
路径空格是另一处。JDK 默认装在C:\Program Files\Java\...下,JAVA_HOME带空格时,凡是没加引号的命令都会在空格处被切断,报一个跟真实原因完全无关的错误。所有引用%JAVA_HOME%的地方一律加双引号,养成习惯就行。
4.2 -encoding 和 file.encoding 是两件事
这两个参数经常被当成一个。-encoding只在编译期起作用,决定 javac 用什么字符集去解码源文件;file.encoding是运行期 JVM 的默认字符集,影响new String(byte[])、FileReader、控制台输出这些行为。
老示例源码多为 GBK,用默认的 UTF-8 去编译,轻则中文注释变乱码,重则直接报unmappable character for encoding UTF8并中断。反过来,运行期读 properties 又是另一套逻辑:Properties.load(InputStream)按 ISO-8859-1 解析,JDK 7 还没有默认 UTF-8 的加载方式,所以中文属性值必须写成\uXXXX转义,或者改用load(Reader)显式指定编码。
:: 编译期:告诉 javac 源码是 GBK "%JAVA_HOME%\bin\javac" -encoding GBK -d out @sources.txt :: 运行期:让 JVM 默认字符集跟控制台对齐,避免输出乱码 chcp 936 "%JAVA_HOME%\bin\java" -Dfile.encoding=GBK -cp out 主类名chcp 936把控制台代码页切成简体中文,只影响当前窗口的显示,不改系统设置。这两条命令解决的是两个不同环节的问题,只改其中一个,乱码往往还在。
4.3 外观与高 DPI:界面「看着不对」的三个来源
SwingSet2 里切换外观后样式大变,那是设计如此,不是渲染坏了。真正需要处理的是另外两件事。
一是默认外观。不指定时 Swing 用 Metal,界面风格停留在 2000 年代初,很多人第一眼以为是显示异常。想固定成系统风格可以显式指定:
"%JAVA_HOME%\bin\java" -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel -cp "SwingSet2.jar;swinglafs.jar" SwingSet2二是 Windows 的显示缩放。系统设成 125% 或 150% 时,老 Swing 应用不做 DPI 适配,控件会错位、字体发虚。JDK 7 在 Windows 上提供了开关:
| 参数 | 作用 | 适用场景 |
|---|---|---|
-Dsun.java2d.dpiaware=false | 关闭 DPI 感知,交给系统整体拉伸 | 控件错位、布局挤在一起 |
-Dsun.java2d.dpiaware=true | 由 JVM 自己按 DPI 缩放 | 文字发虚但布局正常 |
-Dswing.defaultlaf=... | 指定默认外观 | 界面风格与预期不符 |
-Dfile.encoding=GBK | 设定运行期默认字符集 | 控制台或界面中文乱码 |
调这两个 DPI 参数时最好一次只改一个,同时改会分不清是哪个起了作用。
4.4 编译级别与安全边界
这些示例是按 Java 7 语法写的,用-source 1.7 -target 1.7编译最稳。如果某台机器上的默认 javac 版本更高,加上-source 1.7会看到source value 7 is obsolete之类的警告,那只是提示,不影响产物;但如果示例里带了自己写的构建脚本、里面还写着-source 1.4,就会直接失败,得先把脚本里的级别改过来。
还有一层必须说清:7u5 是 2012 年的更新版本,之后的公共修复一概没有。这套东西的正确用法是断网或隔离环境里做学习与复现,别把它写进系统级JAVA_HOME,更别拿它跑任何对外服务。我的做法是给它单开一个 cmd 会话,用完就关,系统环境变量里始终指向受支持的版本。
5. 避坑与排查:五个把 demo 跑崩的常见操作
5.1 双击 jar 没反应,命令行一跑就出堆栈
现象:资源管理器里双击某个 jar,鼠标转一圈,什么都没发生。
原因:.jar的文件关联指向了javaw.exe,它不带控制台,任何异常都被吞掉,所以表现成「毫无反应」。
解决:一律用命令行java -jar或java -cp启动,让堆栈打到屏幕上;想确认关联到哪个程序,用assoc .jar和ftype jarfile查一眼。这一条对排查所有 Java 桌面程序都适用。
5.2 NoClassDefFoundError:类明明在 jar 里
现象:Exception in thread "main" java.lang.NoClassDefFoundError: SwingSet2,但dir明明能看到SwingSet2.jar。
原因:-cp只写了 jar 文件名,而当前工作目录不是 jar 所在目录,或者用了 Linux 风格的冒号分隔。Windows 下 classpath 分隔符是分号,路径是相对当前工作目录解析的。
解决:先cd /d到 jar 所在目录再执行,或者-cp里直接写绝对路径并加引号。分号和冒号这个差异,跨平台拷命令时几乎必踩。
5.3 编译中断在 unmappable character
现象:javac 报unmappable character for encoding UTF8,或者编译过了但界面上的中文全是问号。
原因:-encoding和源码实际编码不一致。demos 里同一批文件也可能混着不同年代的编码,尤其是带中文注释的那几个。
解决:先用编辑器确认编码再决定-encoding GBK还是-encoding UTF-8;实在分不清就两个各试一次,看哪个不报错。注意这一步只解决编译,运行期乱码还得配-Dfile.encoding,两者别混。
5.4 appletviewer 打开一片空白
现象:appletviewer启动了,窗口里什么都没有,或者控制台抛安全异常。
原因:applet 的 HTML 里codebase是相对路径,appletviewer按当前工作目录解析,目录不对就加载不到 class;另外 applet 运行在受限上下文里,本地文件读写会被拦。
解决:cd到 html 文件所在目录再执行appletviewer xxx.html;涉及本地资源的示例,别指望它能像普通应用那样读写磁盘。想在现代环境里复现 applet,只有appletviewer这一条路,浏览器侧已经不通了。
5.5 界面能开,但控件挤在一起、字发虚
现象:在 2K 或 4K 屏上,示例的按钮重叠、文字边缘模糊,截图给别人看对方却说正常。
原因:Windows 显示缩放不是 100%,而老 Swing 应用默认不处理 DPI 变化。
解决:先用-Dsun.java2d.dpiaware=false试,界面会由系统整体拉伸,布局恢复正常但可能略微模糊;再试true,文字清晰但布局可能仍挤。两者取其一,别指望在老代码上两全——要彻底解决只能改布局代码,那是另一件事了。
6. 把它当教材用:从 Java2D 示例里抠出一套可复用的绘制骨架
这批示例最有价值的用法,不是把它们当程序跑,而是当参考实现读。Java2D那个目录里,每个页签对应一个独立的绘制主题,结构高度一致:准备一个BufferedImage做离屏缓冲,拿到它的Graphics2D,设抗锯齿和渲染提示,画完再一次性贴到组件上。这套「离屏缓冲 + 渲染提示 + 一次贴图」的骨架,放到今天的任何绘图需求里依然成立。
我照着它抄出来的最小骨架大致是这样,重点在三个地方:渲染提示的设置顺序、dispose()的调用、以及绘制逻辑和组件重绘的分离。
// 离屏缓冲 + 渲染提示,骨架来自 Java2D 示例的组织方式 BufferedImage buffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = buffer.createGraphics(); try { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 抗锯齿必须在绘制前设 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); // 细线不抖 g2.setColor(Color.WHITE); g2.fillRect(0, 0, w, h); // 真正的绘制逻辑放这里,和组件重绘解耦 } finally { g2.dispose(); // 必须释放,否则高频重绘会持续吃显存/堆 }TYPE_INT_ARGB带透明通道,示例里凡是做叠加效果的都用的这个类型;如果确定不需要透明,换成TYPE_INT_RGB更快。KEY_ANTIALIASING一定要在绘制动作之前设,画完再设没有任何效果,这是我在示例代码里对照出来的第一个细节。dispose()写在finally里,是因为高频重绘场景下漏掉它,几秒钟就能把内存吃满,而这个错误不会立刻报出来,只会在几分钟后突然卡死。
验证改造是否等价,有个很省事的办法:跑示例时加上-Dsun.java2d.trace=count,退出时会把各类绘制操作的次数打出来,和你自己实现的计数对比一下,差一个数量级就说明某处走了低效路径(比如每帧重建BufferedImage,或者忘了设双缓冲)。
| 改造步骤 | 具体动作 | 判断标准 |
|---|---|---|
| 抽骨架 | 把示例里离屏缓冲那段单独拎出来 | 去掉业务绘制后仍能编译运行 |
| 换数据源 | 把示例的固定图形换成自己的数据 | 画面随数据变化,无残留 |
| 加计数 | 跑-Dsun.java2d.trace=count对比 | 绘制次数与原示例同量级 |
从那以后,我每次要动老 Swing 的绘制代码,都会先把对应示例原样跑一遍、截个图,再改自己的实现,改完拿两张图逐像素比。这套笨办法救过我很多次——渲染问题最怕的不是崩,是「看起来差不多」。希望帮到你。
本文还有配套的精品资源,点击获取