文章目錄
- 一、單元測試:JUnit框架精要
- 1.1 單元測試核心概念
- 1.2 JUnit快速入門實戰
- 基礎步驟:
- 斷言機制驗證結果
- 1.3 JUnit核心注解解析
- 二、反射機制:框架設計的基石
- 2.1 反射核心概念
- 2.2 獲取Class對象的三種方式
- 2.3 反射操作類成分
- 獲取并執行構造器
- 操作成員變量
- 調用成員方法
- 2.4 反射高級應用
- 突破泛型限制
- 開發通用對象框架
- 三、注解:元編程利器
- 3.1 注解基礎概念
- 3.2 元注解:注解的注解
- 3.3 注解解析實戰
- 3.4 反射應用場景:模擬JUnit測試框架
- 四、動態代理:優雅的增強方案
- 4.1 代理模式核心思想
- 4.2 JDK動態代理實現
- 定義接口與實現類
- 創建代理工具類
- 使用代理對象
- 4.3 動態代理應用:性能監控
- 五、總結:四大技術的關聯與應用
本文全面解析Java高級技術核心內容:單元測試、反射機制、注解應用與動態代理實現,通過理論講解與代碼實踐助你掌握框架底層原理
一、單元測試:JUnit框架精要
1.1 單元測試核心概念
單元測試是針對**最小功能單元(方法級別)**編寫的測試代碼,用于驗證功能正確性。傳統main方法測試存在三大痛點:
- 無法靈活選擇測試方法
- 不能自動生成測試報告
- 測試過程無法自動化
JUnit作為第三方開源測試框架,完美解決了這些問題:
- ? 支持選擇性執行測試方法或批量執行
- ? 自動生成可視化測試報告(綠色成功/紅色失敗)
- ? 高度靈活的測試代碼編寫
1.2 JUnit快速入門實戰
基礎步驟:
- 創建測試類
- 編寫公共無參無返回值的測試方法
- 使用@Test注解標記測試方法(idea 可以直接導入,Alt+Enter)
- 在測試方法中調用被測代碼(在@Test的方法任務地方右擊,點擊run 方法名)
// StringUtil工具類
public class StringUtil {public static void printNumber(String name) {System.out.println("名字長度:" + name.length());}
}// 測試類
public class StringUtilTest {@Testpublic void testPrintNumber() {StringUtil.printNumber("admin");StringUtil.printNumber(null); // 測試異常情況}
}
斷言機制驗證結果
@Test
public void testGetMaxIndex() {int index = StringUtil.getMaxIndex("admin");// 斷言預測結果:期望值4, 實際值indexAssert.assertEquals("方法內部有Bug", 4, index);
}
注意:很多個測試類中多個測試方法,可以直接點擊項目,右擊run ‘All Tests’
1.3 JUnit核心注解解析
注解 | JUnit4 | JUnit5 | 執行時機 |
---|---|---|---|
初始化 | @Before | @BeforeEach | 每個@Test方法前執行 |
清理 | @After | @AfterEach | 每個@Test方法后執行 |
全局初始化 | @BeforeClass | @BeforeAll | 所有測試方法前執行(static) |
全局清理 | @AfterClass | @AfterAll | 所有測試方法后執行(static) |
資源管理實戰:
public class ResourceTest {private static Socket socket;@BeforeClasspublic static void init() {socket = new Socket(); // 初始化資源}@AfterClasspublic static void cleanup() {socket.close(); // 釋放資源}@Testpublic void testNetwork() {// 使用socket進行測試}
}
二、反射機制:框架設計的基石
2.1 反射核心概念
反射是在運行時獲取類的字節碼對象(Class對象),并動態解析類的全部成分:
- 🏗? 構造器(Constructor對象)
- 📦 成員變量(Field對象)
- ?? 成員方法(Method對象)
應用場景:
- IDE代碼提示功能
- Spring框架的IoC容器
- MyBatis的ORM映射
- 通用工具類開發
2.2 獲取Class對象的三種方式
// 1. 類名.class
Class c1 = Student.class;// 2. Class.forName("全類名")
Class c2 = Class.forName("com.example.Student");// 3. 對象.getClass()
Student s = new Student();
Class c3 = s.getClass();System.out.println(c1 == c2); // true
System.out.println(c2 == c3); // true
2.3 反射操作類成分
獲取并執行構造器
Class<Cat> catClass = Cat.class;// 獲取私有構造器
Constructor<Cat> constructor = catClass.getDeclaredConstructor(String.class, int.class);// 暴力反射(解除私有限制)
constructor.setAccessible(true); // 執行構造器創建實例
Cat cat = constructor.newInstance("Tom", 3);
操作成員變量
Field nameField = catClass.getDeclaredField("name");
nameField.setAccessible(true);// 設置字段值
nameField.set(cat, "Jerry");// 獲取字段值
String name = (String) nameField.get(cat);
調用成員方法
Method runMethod = catClass.getDeclaredMethod("run");
runMethod.setAccessible(true);// 調用無參方法
runMethod.invoke(cat);// 調用有參方法
Method eatMethod = catClass.getDeclaredMethod("eat", String.class);
eatMethod.setAccessible(true);
String result = (String) eatMethod.invoke(cat, "fish");
2.4 反射高級應用
突破泛型限制
// 編譯時泛型檢查
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
// list.add("字符串"); // 編譯報錯// 運行時通過反射繞過泛型檢查
Method addMethod = ArrayList.class.getDeclaredMethod("add", Object.class);
addMethod.invoke(list, "字符串"); // 成功添加
開發通用對象框架
public class ObjectFrame {public static void saveObject(Object obj) throws Exception {Class<?> c = obj.getClass();Field[] fields = c.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);//禁止檢查訪問控制String fieldName = field.getName();Object value = field.get(obj);// 寫入字段名和值到文件}}
}// 使用示例
Student stu = new Student("張三", 20);
ObjectFrame.saveObject(stu);
三、注解:元編程利器
3.1 注解基礎概念
注解(Annotation)是JDK5引入的代碼標記機制,用于對類、方法、字段等進行標注。核心作用:
- 🔖 標記程序元素
- 💡 提供元數據信息
- ?? 驅動特殊處理邏輯
自定義注解格式:
public @interface MyAnnotation {// 屬性聲明String value(); int count() default 1;String[] tags();
}
3.2 元注解:注解的注解
元注解用于修飾自定義注解:
元注解 | 作用 | 常用值 |
---|---|---|
@Target | 指定注解使用范圍 | TYPE, FIELD, METHOD等 |
@Retention | 指定注解生命周期 | SOURCE, CLASS, RUNTIME |
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {String value(); // 書名double price() default 100;String[] authors(); // 作者數組
}
3.3 注解解析實戰
@Book(value = "Java核心技術", authors = {"Cay S. Horstmann"})
public class Textbook {@Book(value = "Effective Java", price = 128.0, authors = {"Joshua Bloch"})public void recommend() {}
}// 解析類注解
Class<Textbook> clazz = Textbook.class;
if (clazz.isAnnotationPresent(Book.class)) {Book book = clazz.getAnnotation(Book.class);System.out.println("書名: " + book.value());
}// 解析方法注解
Method method = clazz.getMethod("recommend");
if (method.isAnnotationPresent(Book.class)) {Book book = method.getAnnotation(Book.class);System.out.println("價格: " + book.price());
}
3.4 反射應用場景:模擬JUnit測試框架
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {}public class TestRunner {public static void main(String[] args) throws Exception {Class<?> testClass = MyTestClass.class;Object instance = testClass.newInstance();for (Method method : testClass.getDeclaredMethods()) {if (method.isAnnotationPresent(MyTest.class)) {method.invoke(instance); // 執行測試方法}}}
}
四、動態代理:優雅的增強方案
4.1 代理模式核心思想
當目標對象無法或不想直接完成操作時,通過代理對象控制對目標對象的訪問:
- 💼 代理對象持有目標對象引用
- 🔄 代理對象攔截方法調用
- ? 在方法執行前后添加額外操作
4.2 JDK動態代理實現
定義接口與實現類
public interface Star {String sing(String song);void dance();
}public class BigStar implements Star {private String name;public BigStar(String name) {this.name = name;}@Overridepublic String sing(String song) {return name + "演唱:" + song;}@Overridepublic void dance() {System.out.println(name + "跳舞");}
}
創建代理工具類
public class ProxyUtil {public static Star createProxy(BigStar target) {return (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),new Class[]{Star.class},(proxy, method, args) -> {// 前置增強if ("sing".equals(method.getName())) {System.out.println("準備話筒,收費20萬");} else if ("dance".equals(method.getName())) {System.out.println("準備場地,收費100萬");}// 調用目標方法Object result = method.invoke(target, args);// 后置增強System.out.println("表演結束,結算費用");return result;});}
}
使用代理對象
public static void main(String[] args) {BigStar star = new BigStar("楊超越");Star proxy = ProxyUtil.createProxy(star);String result = proxy.sing("卡路里");System.out.println(result);proxy.dance();
}
4.3 動態代理應用:性能監控
public class PerformanceProxy {public static UserService createProxy(UserService target) {return (UserService) Proxy.newProxyInstance(PerformanceProxy.class.getClassLoader(),new Class[]{UserService.class},(proxy, method, args) -> {long start = System.currentTimeMillis();Object result = method.invoke(target, args);long end = System.currentTimeMillis();System.out.println(method.getName() + "方法執行耗時: " + (end - start) + "ms");return result;});}
}// 使用示例
UserService userService = new UserServiceImpl();
UserService proxy = PerformanceProxy.createProxy(userService);
proxy.login("admin", "123456");
五、總結:四大技術的關聯與應用
技術 | 核心能力 | 典型應用場景 |
---|---|---|
單元測試 | 自動化驗證代碼邏輯 | 保障代碼質量,回歸測試 |
反射 | 運行時動態解析類結構 | 框架設計,動態代碼生成 |
注解 | 聲明式配置程序元素 | 簡化配置,驅動框架行為 |
動態代理 | 無侵入增強對象功能 | AOP實現,性能監控,事務管理 |
技術聯動示例:
- 使用注解標記測試方法(@Test)
- 通過反射解析測試類信息
- 利用動態代理增強測試方法(添加事務控制)
- 通過單元測試驗證功能正確性
掌握這四大Java高級技術,不僅能編寫更健壯高效的代碼,更能深入理解主流框架的設計思想,為成為架構師奠定堅實基礎。
學習建議:
- 先掌握單元測試保證代碼質量
- 深入理解反射機制原理
- 練習自定義注解及解析
- 動手實現動態代理案例
- 研究Spring等框架的源碼實現