Java反射與動態代理學習筆記

Java 反射與動態代理學習筆記

反射概述

反射允許對成員變量、成員方法和構造方法進行編程訪問,提供了在運行時分析類和對象的能力。

獲取Class對象的三種方式

方式代碼示例說明
Class.forName()Class.forName("全類名")通過類的全限定名獲取Class對象
對象.getClass()對象.getClass()通過對象實例獲取Class對象
類名.class類名.class通過類字面常量獲取Class對象
// 1. Class.forName("全類名")
Class clazz1 = Class.forName("com.zzz.Student");
System.out.println(clazz1);// 2. 對象.getClass()
ReflectionDemo reflectionDemo = new ReflectionDemo();
Class clazz2 = reflectionDemo.getClass();// 3. 類名.class
Class clazz3 = ReflectionDemo.class;// 三種方式獲取的Class對象是相同的
System.out.println(clazz1 == clazz2); // true
System.out.println(clazz1 == clazz3); // true

反射操作構造方法

Class類中獲取構造方法的方法

方法說明
Constructor<?>[] getConstructors()返回所有公共構造方法對象的數組
Constructor<?>[] getDeclaredConstructors()返回所有構造方法對象的數組
Constructor<T> getConstructor(Class<?>... parameterTypes)返回單個公共構造方法對象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)返回單個構造方法對象

Constructor類中創建對象的方法

方法說明
T newInstance(Object... initargs)根據指定的構造方法創建對象
setAccessible(boolean flag)設置為true,表示取消訪問檢查
// 獲取所有公共構造方法
Constructor[] constructors = clazz1.getConstructors();
for (Constructor c : constructors) {System.out.println(c);
}
// 輸出:
// public com.zzz.Student()
// public com.zzz.Student(java.lang.String,int)// 獲取所有構造方法(包括私有和受保護的)
Constructor[] allConstructors = clazz1.getDeclaredConstructors();
for (Constructor c : allConstructors) {System.out.println(c);
}
// 輸出:
// public com.zzz.Student()
// private com.zzz.Student(int)
// protected com.zzz.Student(java.lang.String)
// public com.zzz.Student(java.lang.String,int)// 獲取特定構造方法
Constructor constructor = clazz1.getConstructor(String.class, int.class);
System.out.println(constructor); // public com.zzz.Student(java.lang.String,int)// 獲取私有構造方法
Constructor privateConstructor = clazz1.getDeclaredConstructor(int.class);
System.out.println(privateConstructor);// 使用構造方法創建對象
constructor.setAccessible(true); // 臨時取消權限校驗
Student stu = (Student) constructor.newInstance("張三", 18);
System.out.println(stu);

反射操作成員變量

Class類中獲取成員變量的方法

方法說明
Field[] getFields()返回所有公共成員變量對象的數組
Field[] getDeclaredFields()返回所有成員變量對象的數組
Field getField(String name)返回單個公共成員變量對象
Field getDeclaredField(String name)返回單個成員變量對象

Field類中操作成員變量的方法

方法說明
void set(Object obj, Object value)給指定對象的字段賦值
Object get(Object obj)獲取指定對象的字段值
String getName()獲取字段名稱
Class<?> getType()獲取字段類型
int getModifiers()獲取字段修飾符
// 獲取所有公共成員變量
Field[] publicFields = clazz1.getFields();
for (Field f : publicFields) {System.out.println(f);
}
// 輸出: public java.lang.String com.zzz.Student.gender// 獲取所有成員變量(包括私有)
Field[] allFields = clazz1.getDeclaredFields();
for (Field f : allFields) {System.out.println(f);
}
// 輸出:
// private java.lang.String com.zzz.Student.name
// private int com.zzz.Student.age
// public java.lang.String com.zzz.Student.gender// 獲取特定成員變量
Field ageField = clazz1.getDeclaredField("age");
System.out.println(ageField); // private int com.zzz.Student.age// 獲取成員變量信息
String fieldName = ageField.getName();
System.out.println(fieldName); // ageClass fieldType = ageField.getType();
System.out.println(fieldType); // intint modifiers = ageField.getModifiers();
System.out.println(modifiers); // 2 (表示private)// 獲取和設置字段值
Student student = new Student("張三", 18, "男");
ageField.setAccessible(true); // 訪問私有字段需要取消訪問檢查
int ageValue = (int) ageField.get(student);
System.out.println(ageValue); // 18// 修改字段值
ageField.set(student, 19);
System.out.println(student); // Student{name='張三', age=19, gender='男'}

反射操作成員方法

Class類中獲取成員方法的方法

方法說明
Method[] getMethods()返回所有公共成員方法對象的數組(包括父類方法)
Method[] getDeclaredMethods()返回所有成員方法對象的數組(僅本類方法)
Method getMethod(String name, Class<?>... parameterTypes)返回單個公共成員方法對象
Method getDeclaredMethod(String name, Class<?>... parameterTypes)返回單個成員方法對象

Method類中調用方法的方法

方法說明
Object invoke(Object obj, Object... args)調用方法
String getName()獲取方法名稱
Class<?> getReturnType()獲取方法返回值類型
Class<?>[] getParameterTypes()獲取方法參數類型數組
Class<?>[] getExceptionTypes()獲取方法異常類型數組
int getModifiers()獲取方法修飾符
// 獲取所有公共方法(包括父類方法)
Method[] publicMethods = clazz1.getMethods();
for (Method m : publicMethods) {System.out.println(m);
}// 獲取所有方法(僅本類方法)
Method[] allMethods = clazz1.getDeclaredMethods();
for (Method m : allMethods) {System.out.println(m);
}// 獲取特定方法
Method sleepMethod = clazz1.getMethod("sleep");
System.out.println(sleepMethod);// 獲取帶參數的方法
Method eatMethod = clazz1.getDeclaredMethod("eat", String.class);
System.out.println(eatMethod);// 獲取方法信息
int methodModifiers = eatMethod.getModifiers();
System.out.println(methodModifiers);String methodName = eatMethod.getName();
System.out.println(methodName); // eatClass returnType = eatMethod.getReturnType();
System.out.println(returnType); // class java.lang.StringClass[] parameterTypes = eatMethod.getParameterTypes();
for (Class c : parameterTypes) {System.out.println(c); // class java.lang.String
}Class[] exceptionTypes = eatMethod.getExceptionTypes();
for (Class c : exceptionTypes) {System.out.println(c); // class java.io.IOException, class java.lang.ClassNotFoundException
}// 調用方法
Student student = new Student("張三", 18, "男");
eatMethod.setAccessible(true); // 訪問私有方法需要取消訪問檢查
Object result = eatMethod.invoke(student, "西風");
System.out.println(result); // 吃奧里給
import java.io.IOException;public class Student {private String name;private int age;public String gender;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}protected Student(String name) {this.name = name;}private Student(int age) {this.age = age;}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}// Getter和Setter方法public String getName() { return name; }public void setName(String name) { this.name = name; }public int getAge() { return age; }public void setAge(int age) { this.age = age; }public String getGender() { return gender; }public void setGender(String gender) { this.gender = gender; }@Overridepublic String toString() {return "Student{name='" + name + "', age=" + age + ", gender='" + gender + "'}";}public void sleep() {System.out.println("睡覺");}private String eat(String something) throws IOException, ClassNotFoundException {System.out.println("吃" + something);return "吃奧里給";}
}

反射與配置文件結合

利用反射與配置文件結合的方式,可以動態創建對象并調用方法,提高代碼的靈活性。

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// 1. 讀取配置文件Properties properties = new Properties();FileInputStream fis = new FileInputStream("day27-Reflection\\src\\prop.properties");properties.load(fis);fis.close();System.out.println(properties);// 2. 獲取全類名和方法名String methodName = properties.getProperty("method");String className = properties.getProperty("className");System.out.println(className);System.out.println(methodName);// 3. 利用反射創建對象Class clazz = Class.forName(className);Constructor constructor = clazz.getConstructor();Object obj = constructor.newInstance();System.out.println(obj);// 4. 獲取并調用方法Method method = clazz.getDeclaredMethod(methodName);method.setAccessible(true);method.invoke(obj);}
}

配置文件示例(prop.properties):

className=com.zzz.demo.Student
method=study

動態代理

動態代理可以在運行時創建代理對象,對方法調用進行攔截和處理。

代理接口

public interface Star {// 唱歌String sing();// 跳舞void dance();
}

被代理類

public class BigStar implements Star {private String name;public BigStar() {}public BigStar(String name) {this.name = name;}// 唱歌@Overridepublic String sing() {System.out.println(name + "正在唱歌");return "謝謝";}// 跳舞@Overridepublic void dance() {System.out.println(name + "正在跳舞");}// Getter和Setter省略
}

代理工具類

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil {/*** JDK創建代理對象* Java.lang.reflect.Proxy類中提供了為對象產生代理對象的方法* * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)* 參數一:用于指定用哪個類加載器,去加載生成的代理類* 參數二:指定接口,這些接口用于指定生成的代理有哪些方法* 參數三:用來指定生成的代理對象要干什么事*/public static Star createProxy(BigStar bigStar) {Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),new Class[]{Star.class},new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*** proxy 第一個參數:代理的對象* method 第二個參數:代理對象要調用的方法 sing* args 第三個參數:代理對象要調用方法時,傳遞的參數*/if (method.getName().equals("sing")) {System.out.println("代理開始工作,準備話筒,收錢");} else if (method.getName().equals("dance")) {System.out.println("代理開始工作,準備場地,收錢");}// 調用大明星中的唱歌或者跳舞方法Object result = method.invoke(bigStar, args);if (method.getName().equals("sing")) {System.out.println("代理工作結束(唱歌)");} else if (method.getName().equals("dance")) {System.out.println("代理工作結束(跳舞)");}return result;}});return star;}
}

測試代理

public class Test {public static void main(String[] args) {BigStar star = new BigStar("張三");Star proxy = ProxyUtil.createProxy(star);proxy.dance();// 輸出:// 代理開始工作,準備場地,收錢// 張三正在跳舞// 代理工作結束(跳舞)String singResult = proxy.sing();System.out.println(singResult);// 輸出:// 代理開始工作,準備話筒,收錢// 張三正在唱歌// 代理工作結束(唱歌)// 謝謝}
}

總結

反射是Java中強大的特性,它允許程序在運行時檢查類、接口、字段和方法的信息,并能夠動態創建對象、調用方法和訪問字段。結合配置文件使用反射可以提高代碼的靈活性和可擴展性。

動態代理則基于反射機制,允許在運行時創建代理對象,對方法調用進行攔截和處理,常用于AOP編程、日志記錄、事務管理等場景。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96147.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96147.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96147.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

RAG提示詞分解

RAG提示詞分解 System Message # 智能問答助手&#xff08;RAG系統提示&#xff09;## 角色定義 您是"智能問答助手"&#xff0c;專門基于提供的上下文信息回答用戶問題。## 核心規則 1. **嚴格基于上下文**&#xff1a;僅使用用戶提供的<context>中的信息&…

YOLOv8 在 Intel Mac 上的 Anaconda 一鍵安裝教程

YOLOv8 在 Intel Mac 上的 Anaconda 一鍵安裝教程 本文適用于 Intel 芯片 Mac&#xff0c;通過 Anaconda 快速搭建 YOLOv8 環境&#xff0c;支持 CPU 推理與 Notebook 可視化。 全程一鍵安裝&#xff0c;適合小白和入門用戶。 &#x1f4d1; 目錄 環境準備 一鍵安裝腳本 運行…

Spring 日志文件

Spring 日志文件 文章目錄Spring 日志文件日志有什么用&#xff1f;日志怎么用&#xff1f;自定義日志在程序中獲取日志對象常用日志框架說明使用日志對象打印日志日志格式說明日志級別日志級別有啥用日志級別分類和使用日志持久化保存更簡單的日志輸出——lomboklombok更多注解…

五、誤差反向傳播法(上)

上一章中&#xff0c;我們介紹了神經網絡的學習&#xff0c;并通過數值微分計算了神經網絡的權重參數的梯度&#xff08;嚴格來說&#xff0c;是損失函數關于權重參數的梯度&#xff09;。數值微分雖然簡單&#xff0c;也容易實現&#xff0c;但缺點是計算上比較費時間。本章我…

Rust Axum 快速上手指南(靜態網頁和動態網頁2024版)

本文基于 Axum 0.7.5&#xff08;當前穩定版&#xff09;、tower-http 0.5.2、MiniJinja 0.7.2 編寫&#xff0c;涵蓋生產環境核心場景&#xff1a;tower-http Layer 疊加與數據傳遞、靜態網頁服務、MiniJinja 動態模板渲染&#xff0c;并重點解析請求 / 應答在多 Layer 中的流…

Golang語言設計理念

起源 Golang語言始于2007年&#xff0c;是一門編譯型、靜態類型、并發友好 的語言&#xff0c;由Robert Griesemer&#xff08; 羅伯特格里森、圖靈獎獲得者、C 語法聯合發明人、Unix 之父&#xff09;、Rob Pike&#xff08; 羅布派克、Plan 9 操作系統領導者、UTF-8 編碼的最…

深入掌握 nsenter:Linux命名空間操作的利器

#作者&#xff1a;朱雷 文章目錄1、簡介2、功能與用途2.1. 核心功能2.1.1. 進入命名空間2.1.2. 支持多種命名空間2.1.3. 容器調試3、安裝3.1. 依賴包3.2. 權限要求3.3. 命令用法與示例3.3.1. 基本語法3.3.2. 常用選項包括&#xff1a;3.3.3. 示例4、 應用場景與優勢4.1. 容器調…

Ubuntu Qt x64平臺搭建 arm64 編譯套件

環境&#xff1a; 主機平臺&#xff1a;Ubuntu22.04.5 x86_64 目標平臺&#xff1a;IMX8QM Ubuntu22.04.5 arm64 Qt版本&#xff1a;Qt6.5.3 LST GUI實現&#xff1a;QML 一、獲取Ubuntu22.04.5 x86_64 系統鏡像文件 1、鏡像下載與安裝 使用國內鏡像下載對應版本的Ubuntu鏡像…

mysql第五天學習 Mysql全局優化總結

Mysql全局優化總結 從上圖可以看出SQL及索引的優化效果是最好的&#xff0c;而且成本最低&#xff0c;所以工作中我們要在這塊花更多時間。 補充一點配置文件my.ini或my.cnf的全局參數&#xff1a; 假設服務器配置為&#xff1a; CPU&#xff1a;32核內存&#xff1a;64GDISK…

leetcode hot100 二叉搜索樹

二叉搜索樹的第k小的數class Solution:def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:# 二叉搜索樹的中序遍歷是 升序排列的&#xff0c; 求第k小的&#xff0c;即第k個數self.res []def fun(root):if not root:returnfun(root.left)if root:self.res.a…

從Sonnet到Opus:一次解決RAG知識庫流式輸出難題的探索

又到周末&#xff0c;還得消耗消耗 ?? anyrouter 上的Claude資源&#xff0c;萬一哪天都不能用了&#xff0c;也是浪費。 2025/9/5&#xff0c;Claude AI 的母公司 Anthropic 發布了一項新政策&#xff1a;即日起&#xff0c;Anthropic將不再對中國控股公司及其海外子公司開放…

「數據獲取」中國科技統計年鑒(1991-2024)Excel

02、數據詳情數據名稱&#xff1a;《中國科技統計年鑒》&#xff08;1991-2024年&#xff09;數據年份&#xff1a;1991-202403、數據截圖 04、獲取方式&#xff08;獲取方式看綁定的資源&#xff09;

SimLingo:純視覺框架下的自動駕駛視覺 - 語言 - 動作融合模型

摘要 本文深入探討了 SimLingo&#xff0c;一個在自動駕駛領域具有開創性意義的視覺-語言-動作一體化模型。SimLingo 創新性地將自動駕駛、語言理解和指令感知控制整合到一個統一的純攝像頭框架中&#xff0c;顯著提升了自動駕駛系統在復雜環境中的感知、決策與執行能力。該模…

第五十四天(SQL注入數據類型參數格式JSONXML編碼加密符號閉合復盤報告)

#SQL注入產生原理&#xff1a; 代碼中執行的SQL語句存在可控變量導致 #常見SQL注入的利用過程&#xff1a; 1、判斷數據庫類型 2、判斷參數類型及格式 3、判斷數據格式及提交 4、判斷數據回顯及防護 5、獲取數據庫名&#xff0c;表名&#xff0c;列名 5、獲取對應數據及…

VMWare上搭建Hive集群

文章目錄1. MySQL安裝2. 安裝Hive集群3. 使用Hive客戶端4. 實戰總結本實戰在VMware上搭建Hive集群&#xff0c;集成MySQL作為元數據存儲&#xff0c;完成Hive環境配置、元數據初始化及HDFS倉庫目錄創建&#xff0c;實現Hive on Hadoop的SQL查詢能力&#xff0c;為大數據分析提供…

Android網絡之WIFI技術網絡模型概述

文章目錄術語1、WLAN與WIFI2、802.11 WIFI無線網絡標準演進3、WIFI5、WIFI6和WIFI7的最高速率對比4、WIFI網絡中的各個角色&#xff08;元件&#xff09;1&#xff09;網絡拓撲架構圖5、802.11權威指南1&#xff09;OSI與TCP/IP2&#xff09;IEEE 802.11協議簇介紹3&#xff09…

游戲中的設計模式——第三篇 簡單工廠模式

5. 簡單工廠模式 5.1 簡單工廠模式的定義 簡單工廠模式的核心是定義一個創建對象的接口&#xff0c;將對象的創建和本身的業務邏輯分離&#xff0c;降低系統的耦合度&#xff0c;使得兩個修改起來相對容易些&#xff0c;當以后實現改變時&#xff0c;只需要修改工廠類即可。 5.…

基于SVN搭建企業內部知識庫系統實踐

一、準備工作 CentOS 7 服務器&#xff1a;確保你有 root 或 sudo 權限&#xff0c;可以訪問該服務器。Windows 客戶端&#xff1a;你將需要在 Windows 上安裝 TortoiseSVN 客戶端來與 SVN 服務器交互。防火墻&#xff1a;確保你的防火墻已開放 3690 端口&#xff0c;用于 SVN…

SQL注入7----(盲注與回顯)

一.前言 在我們的注入語句被帶入數據庫查詢但卻什么都沒有返回的情況我們該怎么辦&#xff1f;例如應用程序就會返回 一個"通用的"的頁面&#xff0c;或者重定向一個通用頁面&#xff08;可能為網站首頁&#xff09;。這時&#xff0c;我們之前學習的SQL注入辦 法就…

尚硅谷宋紅康JVM全套教程(詳解java虛擬機)

https://www.bilibili.com/opus/1071553679925968898 案例7&#xff1a;日均百萬訂單系統JVM參數設置 https://github.com/wei198621/jvm_by_atguigu https://github.com/xftxyz2001/atguigu-jvm/blob/main/JavaYouthdocsJVM/%E7%AC%AC1%E7%AB%A0-JVM%E4%B8%8EJava%E4%BD%…