搭建Java源碼閱讀環境,有兩種類型,一種是調試 Java API 代碼,另一種是深入 Java 底層編譯 C++ 代碼。本文主要還停留在 API 層面,搭建的是閱讀 Java API 代碼的環境。
本文使用的 JDK 是 1.8.0_131。
創建項目和首次編譯:
關於步驟,網上很多可以找到的,我這里就提供兩個鏈接:
創建 Java 項目源碼閱讀環境 here
創建 Maven 項目源碼閱讀環境 here
主要流程:
- 創建空項目(Java 或者 Maven 項目)
- 拷貝安裝jdk的目錄中拷貝 src.zip 解壓到新建的空項目中
- Build 項目
問題一:源值1.5已過時
Error:(131, 21) java: -source 1.5 中不支持 diamond 運算符 (請使用 -source 7 或更高版本以啟用 diamond 運算符),如下圖所示:
原因解析:
Java 版本不對。
解決方法:
1.首先,修改 Settings 中 Java Compiler 配置:
2.然后,修改項目 Modules 模塊中的 Language Level 配置:
關於修改 Language Leve 后的警告:
解決建議:
在 pom.xml 中增加這段配置:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<encoding>UTF-8</encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
問題一解決參考博客:
git下載的項目報錯:Warning:java: 源值1.5已過時, 將在未來所有發行版中刪除;找不到或無法加載主類...
maven 指定java版本1.8
問題二:UNIXToolkit和FontConfigManager 找不到
Error:(27, 15) java: 找不到符號 符號: 類 UNIXToolkit 位置: 程序包 sun.awt
Error:(33, 16) java: 找不到符號 符號: 類 FontConfigManager 位置: 程序包 sun.font
因為Windows環境下缺少了兩個文件導致的,我們需要自己去OpenJDK網站下載 OpenJDK。
給你們 2 個鏈接:
-
OpenJdk sun.awt,找到 UNIXToolkit 並拷貝下來。
-
OpenJdk sun.font,找到 FontConfigManager 並拷貝下來。
下載地址由 JDK8源碼閱讀-WINDOWS下環境搭建 提供!
問題三:com.sun.tools.javac.api不存在
Error:(40, 31) java: 程序包com.sun.tools.javac.api不存在。
1.拷貝 JDK安裝目錄/lib/tools.jar 到 Maven項目根目錄/lib/tools.jar
2.打開 Project Structure -> Libraries 新增本地依賴 tools.jar
引入Junit源碼調試
我不太想在 src/main/java 添加太多的類,所以我選擇引入單元測試,你們可以選擇引入 Junit4,這樣比較簡單
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
我最近了解了 Junit5 和 AssertJ 想要嘗試一下,所以我用的是
<dependencies>
<!-- JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>4.12.1</version>
<scope>test</scope>
</dependency>
<!--AssertJ 流式斷言-->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.17.0</version>
<scope>test</scope>
</dependency>
</dependencies>
然后創建一個測試用例,我這里用的 Junit5 + AssertJ 的測試用例哦,Junit4 使用時會編譯錯誤。
import org.junit.Test;
import org.junit.jupiter.api.DisplayName;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FirstTest {
@Test
@DisplayName("首次測試")
public void first_test() {
List<String> list = new ArrayList<>();
list.add("張三");
list.add("李四");
list.add("王五");
assertThat(list).hasSize(3)
.contains("張三");
}
}
關於引入 Junit5 時如何配置 pom.xml
官網:Junit5 user-guide
GitHub:junit5-jupiter-starter-maven/pom.xml
如果你訪問不了 GitHub:解決mvn test運行Junit5測試用例時檢測不到測試類的問題 ,有截圖。
問題四:Debug總是進入反編譯class
既然是源碼閱讀,我們肯定希望代碼能夠進入我們的類中,而不是進入反編譯的 class 類。
4.1 創建移除 rt.jar 的 Platform SDK
首先,打開 Project Structure,在 SDKs 點擊 +
選擇 JDK8 安裝目錄,創建一個名為 1.8-without-rt 的 SDK, 並從 ClassPath 中移除 rt.jar。
項目之間是共享 SDK 的,因此建議保留原來的 SDK 1.8,然后創建一個新的 1.8-without-rt 來做調試之用
4.2 修改 Project SDK
在 Project Structure 中,切換到 Project Settings 下的 Project 欄,選擇 Project SDK 為剛才新建的 1.8-without-rt
4.3 引入 lib/rt.jar 為本地依賴
引入 lib/rt.jar 是為了解決切換到 1.8-without-rt 導致找不到 sun.misc.Unsafe 等類的問題。
現在,我們的源碼項目的代碼變成首選了。
問題五:程序包sun.reflect.misc不存在
Error:(72,24) java: 程序包sun.reflect.misc不存在
Error:(152,24) java: 程序包javax.crypto不存在
Error:(40,31) java: 程序包com.sun.tools.javac.api不存在
【官方解釋】:javac uses a special symbol table that does not include all Sun-proprietary classes. When javac is compiling code it doesn't link against rt.jar by default. Instead it uses special symbol file lib/ct.sym with class stubs.大意是:javac在編譯時,並不引用 rt.jar,用的是一個特別的symbol table(lib/ct.sym),這個symbol table不包含所有的sun包的類。
【具體原因】:J2SE中的類大致可以划分為以下的各個包:java.,javax.,org.,sun.;除了“sun”包,其它各個包都是Java平台的標准實現,並且今后也將被繼續支持。一般說來,“sun”之類的包並不包含在Java平台的標准中,它與操作系統相關,在不同的操作系統(如Solaris,Windows,Linux,Mac等等)中的實現也各不相同,並且可能隨着J2SE版本不定期變化。因此,直接調用“sun”包的程序代碼並不是100%的Java實現。也就是說:“sun.*”包並不是API公開接口的一部分,調用“sun”包的程序並不能確保工作在所有Java平台上,事實上,這樣的程序並不能工作在今后的Java平台上。
5.1 保證 rt.jar 和 jce.jar 在 lib 中
首先,從 JDK8 安裝目錄\jre\lib 把 jce.jar 和 rt.jar 拷貝到 項目根目錄\lib;
另外,從 JDK8 安裝目錄\lib 把 tools.jar 拷貝到 項目根目錄\lib;
然后,把這 3 個 lib 加入到本地依賴中,和之前 2 次的操作相似
5.2 編輯POM文件
關鍵的是這一段:
<compilerArguments>
<bootclasspath>${project.basedir}/lib/rt.jar;${project.basedir}/lib/jce.jar;${project.basedir}/lib/tools.jar</bootclasspath>
</compilerArguments>
完整的 build 標簽如下:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<compilerArguments>
<bootclasspath>${project.basedir}/lib/rt.jar;${project.basedir}/lib/jce.jar;${project.basedir}/lib/tools.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<!-- JUnit 5 requires Surefire version 2.22.0 or higher -->
<version>2.22.2</version>
</plugin>
</plugins>
</build>
參考博客 Maven編譯項目顯示 程序包com.sun.*包不存在 【原因及三種解決方案】
參考博客 maven編譯時javax.crypto程序包不存在的錯誤
參考博客 “程序包com.sun.tools.javac.util不存在” 問題解決