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

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

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

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

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

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

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

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

記憶技巧

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

獲取 Class 對(duì)象的三種方式

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

Java 提供了三種方式來(lái)獲取 Class 對(duì)象:

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

已知類名時(shí)使用,編譯期就確定,不會(huì)拋出異常。

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

方式二:對(duì)象.getClass()(已有對(duì)象時(shí)使用)

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

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

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

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

Java

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

重要提示

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

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

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

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

Java · Student.java(示例類)

public class Student {
    // 成員變量
    public String name;
    private int age;
    // 無(wú)參構(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:

方法說(shuō)明
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)建對(duì)象
Constructor<?> con = clazz.getConstructor(String.class, int.class);
Object stu = con.newInstance("張三", 18);  // 等價(jià)于 new Student("張三", 18)
System.out.println(stu);
// 3. 使用無(wú)參構(gòu)造創(chuàng)建對(duì)象(簡(jiǎn)便寫法)
Object stu2 = clazz.getDeclaredConstructor().newInstance();
System.out.println(stu2);

小貼士

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

利用反射獲取成員變量

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

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

獲取并操作成員變量

import java.lang.reflect.Field;
Class<?> clazz = Student.class;
// 先創(chuàng)建一個(gè) Student 對(duì)象用于測(cè)試
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

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

利用反射獲取成員方法

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

方法說(shuō)明
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)用無(wú)參 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, "王五"); // 等價(jià)于 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ù)說(shuō)明 method.invoke(obj, arg1, arg2, ...)
第一個(gè)參數(shù):要調(diào)用方法的對(duì)象實(shí)例
后續(xù)參數(shù):方法所需的實(shí)際參數(shù)值
返回值:方法的返回值(如果是 void,則返回 null)

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

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

反射的真正價(jià)值,在于"當(dāng)你不知道要用哪個(gè)類的時(shí)候"。來(lái)看一個(gè)簡(jiǎn)單的框架模擬案例:

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

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

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

使用反射讀取配置并動(dòng)態(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. 使用反射動(dòng)態(tài)創(chuàng)建對(duì)象并調(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,程序就會(huì)操作 Teacher 類,完全不需要修改 Java 代碼重新編譯。這正是 Spring 框架依賴注入(IoC)的基本原理!

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

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

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

? 優(yōu)點(diǎn)

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

? 優(yōu)點(diǎn)

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

?? 缺點(diǎn)

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

?? 缺點(diǎn)

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

一張圖回顧全部知識(shí)點(diǎn)

Java 反射
├── 獲取 Class 對(duì)象
│   ├── 類名.class             ← 編譯期,最安全
│   ├── 對(duì)象.getClass()        ← 有對(duì)象實(shí)例時(shí)用
│   └── Class.forName("全類名") ← 運(yùn)行時(shí),最靈活(框架常用)
│
├── 獲取構(gòu)造方法 (Constructor)
│   ├── getConstructors()      ← 所有 public 構(gòu)造
│   ├── getDeclaredConstructors() ← 所有構(gòu)造(含 private)
│   └── con.newInstance(參數(shù))  ← 創(chuàng)建對(duì)象
│
├── 獲取成員變量 (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)用場(chǎng)景
    ├── Spring IoC 依賴注入
    ├── MyBatis ORM 映射
    ├── JSON 序列化 / 反序列化
    └── 單元測(cè)試框架(JUnit)

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

    SpringBoot整合Canal方法詳解

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

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

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

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

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

    RHEL6.5下JDK1.8安裝教程

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

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

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

最新評(píng)論

巴楚县| 襄城县| 洛南县| 新绛县| 昌乐县| 安阳市| 嘉兴市| 栾城县| 汪清县| 西青区| 玛沁县| 阳新县| 榆树市| 陕西省| 卫辉市| 瑞丽市| 抚顺市| 昌宁县| 伊金霍洛旗| 元谋县| 林甸县| 乐至县| 介休市| 光泽县| 淮南市| 江川县| 海丰县| 观塘区| 英吉沙县| 上犹县| 兴宁市| 乌鲁木齐县| 青海省| 中阳县| 文化| 长岭县| 汉沽区| 申扎县| 衡阳县| 武鸣县| 普定县|