1. CompletableFuture中thenApply()
與thenCompose()
的區別
考察點:組合式異步編程
解析:
- ?**
thenApply()
**:接收前序任務結果,返回普通對象(同步轉換),適用簡單數據處理。 - ?**
thenCompose()
**:接收前序任務結果,返回新的CompletableFuture
(異步嵌套),用于鏈式調用異步任務。
示例:
java
CompletableFuture.supplyAsync(() -> "Hello") .thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World")); // 鏈式異步
?2. Java模塊化系統(JPMS)如何解決“自動模塊”問題?
考察點:模塊化依賴管理
解析:
- ?自動模塊:非模塊化JAR包會被視為自動模塊,導出所有包并讀取所有其他模塊。
- ?解決方案:在
module-info.java
中顯式聲明依賴:java
requires transitive com.example.lib; // 傳遞依賴
?3. 如何用GraalVM將Spring Boot應用編譯為原生鏡像?
考察點:AOT編譯與云原生優化
解析:
- ?添加依賴:
xml
<dependency> <groupId>org.springframework.experimental</groupId> <artifactId>spring-native</artifactId> </dependency>
- ?編譯命令:
bash
mvn spring-boot:build-image
優勢:啟動時間<50ms,內存占用降低60%。
?4. 記錄類型(Records)能否實現Builder模式?
考察點:不可變數據結構設計
解析:
- ?限制:Records默認生成final類,字段不可變,需通過靜態內部類模擬Builder:
java
public record User(Long id, String name) { public static class Builder { private Long id; private String name; // Setter方法 public User build() { return new User(id, name); } } }
?5. 模式匹配在instanceof
和switch
中的性能差異
考察點:新特性底層優化
解析:
- ?**
instanceof
模式匹配**:編譯器生成類型檢查代碼,性能與傳統instanceof
+強制轉型相當。 - ?**
switch
模式匹配**?(Java 21預覽):生成跳表優化,適合多分支場景,性能優于鏈式if-else
。
?6. ZGC的“染色指針”如何實現并發標記?
考察點:低延遲GC原理
解析:
- ?指針元數據:在64位指針中存儲標記位、重定位狀態等,無需STW即可更新對象狀態。
- ?讀屏障:在訪問對象時動態修正指針,保證并發標記期間線程安全。
?7. JFR(Java Flight Recorder)如何定位線程阻塞問題?
考察點:性能分析工具
步驟:
- 錄制JFR數據:
bash
jcmd <pid> JFR.start duration=60s filename=blocking.jfr
- 分析
jdk.JavaMonitorWait
事件,查看持有鎖的線程棧。
?8. 如何用JMH測試StringBuffer
與StringBuilder
的性能差異?
考察點:基準測試實踐
代碼:
java
@BenchmarkMode(Mode.Throughput)
public class StringBenchmark { @Benchmark public void testStringBuffer() { StringBuffer sb = new StringBuffer(); for (int i=0; i<1000; i++) sb.append(i); } // 類似實現StringBuilder測試
}
結論:單線程下StringBuilder
快30%,多線程需考慮鎖競爭。
?9. 密封類(Sealed Classes)在領域驅動設計(DDD)中的應用
考察點:領域模型限制
場景:定義核心領域對象,限制子類擴展:
java
public sealed interface PaymentMethod permits CreditCard, PayPal {}
public final class CreditCard implements PaymentMethod { /* 字段校驗邏輯 */ }
優勢:強制業務規則,避免模型污染。
?10. 虛擬線程(Project Loom)與傳統線程池的資源消耗對比
考察點:輕量級并發模型
數據:
- ?傳統線程:1個線程 ≈ 1MB棧內存,萬級線程消耗GB級內存。
- ?虛擬線程:1個虛擬線程 ≈ 1KB內存,支持百萬級并發。
適用場景:IO密集型服務(如API網關、爬蟲)。
?11. 靜態類初始化陷阱:靜態代碼塊與構造函數的執行順序
考察點:類加載機制
示例:
java
class Parent { static { System.out.println("Parent靜態塊"); } Parent() { System.out.println("Parent構造器"); }
}
class Child extends Parent { static { System.out.println("Child靜態塊"); } Child() { System.out.println("Child構造器"); }
}
// 輸出順序:Parent靜態塊 → Child靜態塊 → Parent構造器 → Child構造器
?12.?Optional.orElse()
與orElseGet()
的性能差異
考察點:延遲計算優化
解析:
- ?**
orElse()
**:無論Optional是否為空,都會執行參數表達式。 - ?**
orElseGet()
**:僅在Optional為空時執行Supplier
邏輯,適合高開銷操作。
?13. 方法句柄(MethodHandle)與反射的性能對比
考察點:底層API優化
數據:
- ?反射調用:每次調用檢查訪問權限,性能較差。
- ?方法句柄:JVM內聯優化,性能接近直接方法調用(快5-10倍)。
示例:
java
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(String.class, "length", MethodType.methodType(int.class));
int len = (int) mh.invokeExact("test"); // len=4
?14. JNI調用的內存泄漏風險及解決方案
考察點:本地方法安全
風險點:
- 未正確釋放
NewGlobalRef
創建的全局引用。 - 本地代碼中直接修改Java對象未同步回JVM。
解決:使用try-finally
塊確保釋放資源,或換用JNA/JNR等安全框架。
?15. 動態代理在Spring AOP中的性能瓶頸
考察點:代理機制優化
問題:JDK動態代理基于接口,CGLIB基于類,后者生成子類可能導致方法final修飾符沖突。
優化:Spring 5默認使用CGLIB,可通過@EnableAspectJAutoProxy(proxyTargetClass=true)
強制使用。
?16. 弱引用(WeakReference)在緩存設計中的誤用場景
考察點:引用類型特性
陷阱:若緩存鍵通過弱引用持有,可能被GC提前回收,導致緩存失效。
方案:使用WeakHashMap
或搭配ReferenceQueue
手動清理。
?17. JVM退出時的鉤子函數(ShutdownHook)執行限制
考察點:JVM生命周期
規則:
- 鉤子函數必須快速執行,超時會被強制終止。
- 已執行
System.exit()
后注冊的鉤子無效。
?18. 常量折疊(Constant Folding)對程序邏輯的潛在影響
考察點:編譯器優化
示例:
java
final int a = 1;
final int b = 2;
System.out.println(a + b); // 編譯時優化為3,字節碼中無加法指令
注意:依賴編譯時常量的計算可能隱藏邏輯錯誤。
?19. 偽共享(False Sharing)在并發計數器的解決方案
考察點:CPU緩存優化
問題:多個線程修改同一緩存行的不同變量,導致緩存失效。
解決:
java
@Contended // JVM參數需加-XX:-RestrictContended
public class Counter { public volatile long value1; public volatile long value2;
}
?20. Java模塊化系統中如何允許第三方庫反射訪問私有字段?
考察點:模塊權限控制
配置:在module-info.java
中開放包:
java
open module com.example.app { opens com.example.internal to spring.core; // 對特定模塊開放
}
風險:過度開放可能導致封裝性破壞。