# JavaSource **Repository Path**: lmw0726/java-source ## Basic Information - **Project Name**: JavaSource - **Description**: JDK8源码学习。 对JDK源码进行注释,并添加到思维导图中,归纳总结。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 11 - **Forks**: 0 - **Created**: 2021-05-15 - **Last Updated**: 2025-09-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: JDK源码 ## README # JDK1.8源码阅读环境搭建 源码的学习者,与大家共勉 >参考 > >1. [曹工力荐:调试 jdk 中 rt.jar 包部分的源码 可自由增加注释,修改代码并debug](https://www.cnblogs.com/grey-wolf/p/12817615.html) >2. [idea中搭建jdk1.8源码阅读环境](https://blog.csdn.net/u010999809/article/details/101922489) ## 1、背景 我们都知道,rt.jar包是java主要功能的实现包,但是在各个IDE中,打开java是无法进行源码编辑的,这样在阅读JDK源码带来许多的不便。那么怎样才可以实现在IDE中对JDK源码进行注释呢? ## 2、需求 首先讨论一下我们需要达成什么样的目标吧。 ### 2.1、运行时关联代码 1. 可以在IDEA中关联我们的源码,确保运行时,源码不会左右横跳到Oracle定义官方jar包中。 ### 2.2、顶部注释 2. 可以在源码中在代码顶部写下自己的注释,这点很重要。 > > 顶部注释类似于这种 > ``` > //比较的是两个对象的地址。 > return (this == obj); > > ``` > 而尾行注释则是这种。 > ``` > return (this == obj);//比较的是两个对象的地址。 > > ``` 我查询了许多搭建JDK源码的相关博客,但是他们都告诉我,只能写在只能在尾部注释,否则debug时,就会出现代码错位 ![debug错位演示1](./src/main/resources/image/debug错位演示1.jpg) 此时我们 **F7**进行下一步时,就会出现下面的这种情况。 ![debug错位演示2](./src/main/resources/image/debug错位演示1.jpg) WTF?竟然没有跳到concat的源码,而是跳到了注释上。这就是JDK源码阅读时,常蹚的坑——debug代码错位。 很明显,尾行注释的方法即不美观,也影响了代码的可读性,所以我们不推荐这种方法。除了这些博主介绍的尾行注释法外,下面要介绍的就是**Debug时加参数**的方法。 ## 3、基础环境 操作系统: Windows 8.1 Java版本: **1.8.0_152** IDEA: IntelliJ IDEA 2019.1.1 ## 4、环境搭建步骤 大多数博主在搭建JDK阅读环境时都推荐使用简单Java项目的方式进行建项目。而我们这里则推荐建立Maven或者Gradle项目的方式进行源码环境的搭建。 ### 4.1、为什么要使用Maven的方式建立项目? 一开始,我也是使用普通Java项目的方式搭建源码阅读环境的。直到我也出现了Debug错位的现象,我开始找各种解决办法。找了许多种办法,解决这种问题的思路就是重新编译一次,并且让IDEA识别修改后的代码。但是无论是Javac编译还是IDEA的Rebuild projecct都没法解决问题。当然也有大佬写了脚本解决了这个问题 [[1](https://blog.csdn.net/u010999809/article/details/102762142)]。但是到我这就水土不服了。 读完曹工的文章了,我找到原因了,原来是Java的类加载机制搞的鬼。由于编译后,Java会优先加载JDK中rt.jar中的源码,之后才会“看到”我们注释的同包同名的类,由于已经存在过了该类,根本就不会加载我们的类。所以使用maven的目的有两个;其一、引用junit的相关类运行注释后的代码。其二、将注释后的源码打包成jar,通过我们的配置,让**BootStrapClassloader**优先加载它。 ### 4.2、新建一个Maven项目 File-> New -> project... -> Maven ![新建maven项目1](./src/main/resources/image/新建Maven项目1.jpg) ![新建maven项目2](./src/main/resources/image/新建Maven项目2.jpg) 确定了Maven项目存放的地方后,FINISH即可。 POM文件的相应配置如下 ![新建maven项目3](./src/main/resources/image/新建Maven项目3.jpg) ### 4.3、导入源码 在资源管理器中打开自己项目路径下的src/main/java,并且进入到java目录。在资源管理器中复制java的源码不会卡死IDEA。 ![导入源码1](./src/main/resources/image/导入源码1.jpg) 打开自己的Java安装路径。找到src.zip,这个压缩文件就是Java的源码了。 ![导入源码2](./src/main/resources/image/导入源码2.png) ![导入源码3](./src/main/resources/image/导入源码3.png) 并不需要导入太多源码,只需要导入java包下的io、lang、math、net、nio、text、time、util等八个包即可。下面是在这两年打算阅读的包。 ![导入源码4](./src/main/resources/image/导入源码4.png) ### 4.4、IDEA设置 为了防止内存溢出,我们可以将堆内存加大,按下**Ctrl**+**Alt**+**S**,弹出Settings页面 ![IDEA设置1](./src/main/resources/image/IDEA设置1.png) 之后点击下面的OK就好了。 ### 4.5、关联源代码 同时按下**Ctrl**+**Alt**+**Shift**+**S**打开项目设置页面。 增加一个新的SDK,并将我们src/main/java下的源码关联到这个SDK中 ![关联源代码1](./src/main/resources/image/关联源码1.png) ![关联源代码2](./src/main/resources/image/关联源码2.png) ![关联源代码3](./src/main/resources/image/关联源码3.png) 将原来关联到压缩包的sourcePath去除掉,并且改成我们自己项目的src/main/java目录。 ![关联源代码4](./src/main/resources/image/关联源码4.png) ![关联源代码5](./src/main/resources/image/关联源码5.png) 为项目关联新增的SDK,并且设置语言特性。 ![关联源代码6](./src/main/resources/image/关联源码6.png) ![关联源代码7](./src/main/resources/image/关联源码7.png) ### 4.6、测试 在src/main下建立一个Main类, ``` public class Main { public static void main(String[] args) { String hello = "Hello "; String world = "world"; String helloworld = hello.concat(world); System.out.println(helloworld); } } ``` 运行这个类,第一次运行,由于需要将源码打包到target/目录下,所以会编译很久,甚至会运行失败。别灰心,运行maven菜单中的Reimport重新运行即可。 但是,此时debug发现,源码标记有Source code does not match the bytecode的提示,这就出现了前面所说的debug错位现象。 那么该如何解决呢? ### 4.7、解决方法 解决方法就是配置运行时的虚拟机参数—— **-Dsun.boot.class.path** 该参数的意思是优先加载指定目录的文件。只要将我们的jar包放在系统JDK的加载顺序之前,debug时,就可以正确地跳到源代码,而不会跳到注释行了。 可以通过以下代码获取该参数的值 ``` String property = System.getProperty("sun.boot.class.path"); String targetClassesPath="D:\\IntelliJIDEAResposity\\JavaSource\\target\\classes"; System.setProperty("sun.boot.class.path",targetClassesPath +";"+ property); System.out.println(System.getProperty("sun.boot.class.path")); ``` 比如,我的参数是长这样的: > -Dsun.boot.class.path="D:\IntelliJIDEAResposity\Java8Source\target\classes;D:\Java\jdk1.8\jre\lib\resources.jar; > D:\Java\jdk1.8\jre\lib\rt.jar;D:\Java\jdk1.8\jre\lib\sunrsasign.jar;D:\Java\jdk1.8\jre\lib\jsse.jar; > D:\Java\jdk1.8\jre\lib\jce.jar;D:\Java\jdk1.8\jre\lib\charsets.jar;D:\Java\jdk1.8\jre\lib\jfr.jar; > D:\Java\jdk1.8\jre\classes" ![配置运行参数1](./src/main/resources/image/配置运行参数1.png) ![配置运行参数2](./src/main/resources/image/配置运行参数2.png) 这里需要配置自己的targetClassesPath。然后将运行结果复制到该方法的虚拟机运行参数即可。 ![targetclasses路径](./src/main/resources/image/targetclasses路径.png) 为了方便测试,我们可以将上面的参数复制到Junit的模板中。大家日常开发时,不要忘记将该参数暂时删除掉。 ![junit模板配置1](./src/main/resources/image/配置Junit模板1.png) ![junit模板配置2](./src/main/resources/image/配置Junit模板2.png)