最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入理解Java反射(超詳細(xì)教程)

 更新時間:2026年05月28日 09:09:00   作者:一條泥憨魚  
本文詳細(xì)解析了Java反射機(jī)制,介紹了運行時概念、獲取Class對象的三種方式,并并探討了反射在反射構(gòu)造方法、成員變量及方法中的的應(yīng)用場景,通過框架模擬案例展示了反射在實際框架設(shè)計中的重要性,感興趣的朋友跟隨小編一起看看吧

?????什么是反射?通俗理解

我們先想一個生活中的例子:你手里有一個神秘的黑盒子,不知道里面裝了什么。正常情況下,你要先看說明書(源碼),才知道它有哪些按鈕、怎么用。

但如果你有一臺"X光機(jī)",不用看說明書,直接對著黑盒子掃一下,就能看清楚里面有哪些零件、每個零件叫什么名字、怎么操作——這臺"X光機(jī)"就是 Java 的反射機(jī)制

// 官方定義Java 反射機(jī)制是指在程序運行時(Runtime),對于任意一個類,都能知道這個類的所有屬性和方法;對于任意一個對象,都能調(diào)用它的任意方法和屬性。這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能,稱為 Java 的反射機(jī)制。

關(guān)鍵詞是"運行時"。普通代碼在編譯時就確定了用哪個類、調(diào)哪個方法。而反射可以在程序跑起來之后,才決定要操作哪個類——這帶來了極大的靈活性,是 Spring、MyBatis 等主流框架的底層核心。

記憶技巧

正常寫代碼:編譯期就確定類和方法 → 安全、快速
使用反射:運行期才確定類和方法 → 靈活、強(qiáng)大

獲取 Class 對象的三種方式

使用反射的第一步,是拿到目標(biāo)類的 Class 對象。你可以把 Class 對象理解為那臺"X光機(jī)"掃描后得到的"類的說明書",里面記錄了該類的一切信息。

Java 提供了三種方式來獲取 Class 對象:

方式一:類名.class(最簡單直接)

已知類名時使用,編譯期就確定,不會拋出異常。

Class<String> clazz = String.class;
System.out.println(clazz); // 輸出: class java.lang.String

方式二:對象.getClass()(已有對象時使用)

當(dāng)你手里已經(jīng)有一個對象實例,可以通過它獲取對應(yīng)的 Class。

String str = "Hello, 反射!";
Class<?> clazz = str.getClass();
System.out.println(clazz); // 輸出: class java.lang.String

方式三:Class.forName("全類名")(最靈活,框架常用)

通過完整類名字符串動態(tài)加載類。類名可以來自配置文件、數(shù)據(jù)庫等,是框架最常用的方式。注意:需要處理 ClassNotFoundException。

Java

try {
    // 全類名 = 包名 + 類名
    Class<?> clazz = Class.forName("java.lang.String");
    System.out.println(clazz); // 輸出: class java.lang.String
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

重要提示

同一個類,無論用哪種方式獲取 Class 對象,得到的都是同一個對象(JVM 中每個類只有一份 Class 對象)。
三種方式的結(jié)果完全相同:String.class == str.getClass() == Class.forName("java.lang.String")

利用反射獲取構(gòu)造方法

拿到 Class 對象后,我們就可以"解剖"這個類了。先來看如何獲取構(gòu)造方法(Constructor)。

首先,我們定義一個示例類 Student,后續(xù)所有例子都基于它:

Java · Student.java(示例類)

public class Student {
    // 成員變量
    public String name;
    private int age;
    // 無參構(gòu)造
    public Student() {}
    // 有參構(gòu)造
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 成員方法
    public void study() {
        System.out.println(name + " 正在學(xué)習(xí)Java!");
    }
    private void sleep() {
        System.out.println(name + " 在睡覺...");
    }
    // getter/setter 省略...
}

常用的獲取構(gòu)造方法 API:

方法說明
getConstructors()獲取所有 public 構(gòu)造方法
getDeclaredConstructors()獲取所有構(gòu)造方法(包括私有)
getConstructor(參數(shù)類型...)獲取指定的 public 構(gòu)造方法
getDeclaredConstructor(參數(shù)類型...)獲取指定的任意構(gòu)造方法

獲取并使用構(gòu)造方法

import java.lang.reflect.Constructor;
Class<?> clazz = Class.forName("Student");
// 1. 獲取所有 public 構(gòu)造方法
Constructor[] constructors = clazz.getConstructors();
for (Constructor c : constructors) {
    System.out.println(c);
}
// 2. 獲取有參構(gòu)造并創(chuàng)建對象
Constructor<?> con = clazz.getConstructor(String.class, int.class);
Object stu = con.newInstance("張三", 18);  // 等價于 new Student("張三", 18)
System.out.println(stu);
// 3. 使用無參構(gòu)造創(chuàng)建對象(簡便寫法)
Object stu2 = clazz.getDeclaredConstructor().newInstance();
System.out.println(stu2);

小貼士

con.newInstance(參數(shù)...) 就是反射版的 new 關(guān)鍵字。參數(shù)類型和順序必須與構(gòu)造方法一致。

利用反射獲取成員變量

反射不僅能創(chuàng)建對象,還能直接讀寫對象的成員變量(Field),即使是 private 修飾的私有變量也能訪問!

方法說明
getFields()獲取所有 public 成員變量
getDeclaredFields()獲取所有成員變量(包括私有)
getField("變量名")獲取指定 public 變量
getDeclaredField("變量名")獲取指定任意變量

獲取并操作成員變量

import java.lang.reflect.Field;
Class<?> clazz = Student.class;
// 先創(chuàng)建一個 Student 對象用于測試
Object stu = clazz.getDeclaredConstructor(String.class, int.class)
                    .newInstance("張三", 18);
// 1. 獲取 public 變量 name 并修改
Field nameField = clazz.getField("name");
nameField.set(stu, "李四");              // 修改 name 值
System.out.println(nameField.get(stu)); // 讀取 name 值 → 李四
// 2. 獲取 private 變量 age
//    ?? 訪問私有變量必須先調(diào)用 setAccessible(true) 暴力破解!
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);          // 取消私有訪問限制(關(guān)鍵?。?
ageField.set(stu, 20);                  // 修改 age 值
System.out.println(ageField.get(stu)); // 讀取 age 值 → 20

?? 重點:setAccessible(true)訪問 private 成員時,必須先調(diào)用 setAccessible(true),否則會拋出 IllegalAccessException。這個操作相當(dāng)于"強(qiáng)制解鎖私有權(quán)限",在框架中非常常見,但在業(yè)務(wù)代碼中要謹(jǐn)慎使用。

利用反射獲取成員方法

反射還可以獲取并調(diào)用任意方法(Method),包括私有方法,甚至可以在不知道方法名的情況下,通過字符串來動態(tài)調(diào)用。

方法說明
getMethods()獲取所有 public 方法(含父類繼承的)
getDeclaredMethods()獲取本類所有方法(不含繼承,含私有)
getMethod("方法名", 參數(shù)類型...)獲取指定 public 方法
getDeclaredMethod("方法名", 參數(shù)類型...)獲取本類指定任意方法

獲取并調(diào)用成員方法

import java.lang.reflect.Method;
Class<?> clazz = Student.class;
Object stu = clazz.getDeclaredConstructor(String.class, int.class)
                    .newInstance("張三", 18);
// 1. 調(diào)用無參 public 方法 study()
Method studyMethod = clazz.getMethod("study");
studyMethod.invoke(stu); // 輸出:張三 正在學(xué)習(xí)Java!
// 2. 調(diào)用帶參方法(假設(shè)有 setName(String name) 方法)
Method setNameMethod = clazz.getMethod("setName", String.class);
setNameMethod.invoke(stu, "王五"); // 等價于 stu.setName("王五")
// 3. 調(diào)用 private 方法 sleep()
Method sleepMethod = clazz.getDeclaredMethod("sleep");
sleepMethod.setAccessible(true);  // 私有方法同樣需要暴力破解
sleepMethod.invoke(stu);           // 輸出:王五 在睡覺...
// 4. 獲取方法的返回值
Method getAgeMethod = clazz.getMethod("getAge");
Object result = getAgeMethod.invoke(stu);
System.out.println("年齡: " + result); // 年齡: 18

method.invoke()

參數(shù)說明 method.invoke(obj, arg1, arg2, ...)
第一個參數(shù):要調(diào)用方法的對象實例
后續(xù)參數(shù):方法所需的實際參數(shù)值
返回值:方法的返回值(如果是 void,則返回 null)

反射的實際作用與應(yīng)用場景

你可能會問:"我直接 new 一個對象不就好了,為什么要用這么麻煩的反射?"

反射的真正價值,在于"當(dāng)你不知道要用哪個類的時候"。來看一個簡單的框架模擬案例:

案例:模擬框架——根據(jù)配置文件動態(tài)創(chuàng)建對象

假設(shè)我們有一個配置文件 config.properties

# 只需修改這里,程序行為就會改變
className=com.example.Student
methodName=study

使用反射讀取配置并動態(tài)執(zhí)行

import java.util.Properties;
import java.io.InputStream;
import java.lang.reflect.*;
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        // 1. 讀取配置文件
        Properties prop = new Properties();
        InputStream is = ReflectDemo.class.getClassLoader()
                              .getResourceAsStream("config.properties");
        prop.load(is);
        // 2. 獲取類名和方法名
        String className  = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");
        // 3. 使用反射動態(tài)創(chuàng)建對象并調(diào)用方法
        //    ? 不修改 Java 代碼,只改配置文件就能切換行為!
        Class<?> clazz = Class.forName(className);
        Object obj = clazz.getDeclaredConstructor().newInstance();
        Method method = clazz.getMethod(methodName);
        method.invoke(obj);
    }
}

現(xiàn)在把配置文件里的 className 改成 com.example.Teacher,程序就會操作 Teacher 類,完全不需要修改 Java 代碼重新編譯。這正是 Spring 框架依賴注入(IoC)的基本原理!

反射在主流框架中的應(yīng)用

Spring IoC:讀取 XML / 注解配置 → 用反射創(chuàng)建 Bean 對象并注入依賴
MyBatis:讀取 SQL 結(jié)果集 → 用反射把列值賦給 Java 對象的字段
Jackson / Gson:JSON 反序列化 → 用反射把 JSON 字段映射到 Java 對象
JUnit:掃描帶 @Test 注解的方法 → 用反射自動執(zhí)行測試方法

反射的優(yōu)缺點總結(jié)

? 優(yōu)點

靈活性強(qiáng):運行時動態(tài)操作類,無需在編譯期確定類型,是框架設(shè)計的基石。

? 優(yōu)點

降低耦合:通過配置文件驅(qū)動,代碼與具體類解耦,修改配置即可切換實現(xiàn)。

?? 缺點

性能開銷:反射涉及動態(tài)解析,比直接調(diào)用慢,頻繁調(diào)用場景應(yīng)緩存 Method / Field 對象。

?? 缺點

安全風(fēng)險:setAccessible(true) 可繞過訪問控制,破壞封裝性,需謹(jǐn)慎使用。

一張圖回顧全部知識點

Java 反射
├── 獲取 Class 對象
│   ├── 類名.class             ← 編譯期,最安全
│   ├── 對象.getClass()        ← 有對象實例時用
│   └── Class.forName("全類名") ← 運行時,最靈活(框架常用)
│
├── 獲取構(gòu)造方法 (Constructor)
│   ├── getConstructors()      ← 所有 public 構(gòu)造
│   ├── getDeclaredConstructors() ← 所有構(gòu)造(含 private)
│   └── con.newInstance(參數(shù))  ← 創(chuàng)建對象
│
├── 獲取成員變量 (Field)
│   ├── getFields()            ← 所有 public 字段
│   ├── getDeclaredFields()    ← 所有字段(含 private)
│   ├── field.get(obj)         ← 讀取值
│   ├── field.set(obj, val)    ← 修改值
│   └── setAccessible(true)   ← 訪問 private 必須調(diào)用!
│
├── 獲取成員方法 (Method)
│   ├── getMethods()           ← 所有 public 方法(含繼承)
│   ├── getDeclaredMethods()   ← 本類所有方法(含 private)
│   ├── method.invoke(obj, args...) ← 調(diào)用方法
│   └── setAccessible(true)   ← 調(diào)用 private 必須調(diào)用!
│
└── 應(yīng)用場景
    ├── Spring IoC 依賴注入
    ├── MyBatis ORM 映射
    ├── JSON 序列化 / 反序列化
    └── 單元測試框架(JUnit)

反射是"高階武器",初學(xué)階段不需要在業(yè)務(wù)代碼中大量使用。但理解反射是讀懂 Spring、MyBatis 等框架源碼的前提。掌握本文的內(nèi)容,你已經(jīng)具備了探索主流框架底層原理的基礎(chǔ)能力!

到此這篇關(guān)于深入理解Java反射(超詳細(xì)教程)的文章就介紹到這了,更多相關(guān)Java反射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談Java中OutOfMemoryError問題產(chǎn)生原因

    淺談Java中OutOfMemoryError問題產(chǎn)生原因

    本文主要介紹了淺談Java中OutOfMemoryError問題產(chǎn)生原因,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Mybatis 多對一查詢的實現(xiàn)方法

    Mybatis 多對一查詢的實現(xiàn)方法

    這篇文章主要介紹了Mybatis 多對一查詢,本文通過場景分析示例代碼相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • Java線程編程中的主線程講解

    Java線程編程中的主線程講解

    這篇文章主要介紹了Java線程編程中的主線程,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • SpringBoot中靜態(tài)資源處理的7個技巧分享

    SpringBoot中靜態(tài)資源處理的7個技巧分享

    在Web應(yīng)用開發(fā)中,靜態(tài)資源(如CSS、JavaScript、圖片等)的處理是一個基礎(chǔ)但重要的環(huán)節(jié),本文將介紹SpringBoot中7種靜態(tài)資源處理技巧,希望對大家有所幫助
    2025-05-05
  • Java8 lambda表達(dá)式2種常用方法代碼解析

    Java8 lambda表達(dá)式2種常用方法代碼解析

    這篇文章主要介紹了Java8 lambda表達(dá)式2種常用方法代碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • SpringBoot整合Canal方法詳解

    SpringBoot整合Canal方法詳解

    這篇文章主要介紹了SpringBoot整合Canal,canal可以用來監(jiān)控數(shù)據(jù)庫數(shù)據(jù)的變化,從而獲得新增數(shù)據(jù),或者修改的數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • java中struts2實現(xiàn)文件上傳下載功能

    java中struts2實現(xiàn)文件上傳下載功能

    這篇文章主要介紹了java中struts2實現(xiàn)文件上傳下載功能的方法,以實例形式分析了struts2文件上傳下載功能的實現(xiàn)技巧與相關(guān)問題,具有一定的參考借鑒價值,需要的朋友可以參考下
    2016-05-05
  • java實現(xiàn)sunday算法示例分享

    java實現(xiàn)sunday算法示例分享

    Sunday算法的思想和BM算法中的壞字符思想非常類似。差別只是在于Sunday算法在匹配失敗之后,是取目標(biāo)串中當(dāng)前和Pattern字符串對應(yīng)的部分后面一個位置的字符來做壞字符匹配,寫了個小例子來實現(xiàn)以下這個算法
    2014-01-01
  • RHEL6.5下JDK1.8安裝教程

    RHEL6.5下JDK1.8安裝教程

    這篇文章主要為大家詳細(xì)介紹了RHEL6.5下JDK1.8安裝教程的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Java實現(xiàn)生成IPv4地址并判斷其合法性

    Java實現(xiàn)生成IPv4地址并判斷其合法性

    這篇文章主要為大家詳細(xì)介紹了如何使用Java實現(xiàn)生成IPv4地址并判斷其合法性,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2026-04-04

最新評論

广河县| 东阿县| 汶上县| 峨山| 南京市| 镶黄旗| 武定县| 宣武区| 玉龙| 上杭县| 磐石市| 甘孜县| 亳州市| 峨眉山市| 靖西县| 绵竹市| 英山县| 西畴县| 礼泉县| 施甸县| 景洪市| 吉水县| 汉寿县| 九江市| 东莞市| 垦利县| 闽清县| 云林县| 湘阴县| 大同县| 民乐县| 万山特区| 临潭县| 洛隆县| 黄陵县| 紫阳县| 宁都县| 娄烦县| 安阳县| 得荣县| 深泽县|