日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 反射机制_基础篇:深入解析JAVA反射机制

發布時間:2023/12/9 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 反射机制_基础篇:深入解析JAVA反射机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

反射的概念

  • java 的放射機制:在程序運行時,程序有能力獲取一個類的所有方法和屬性;并且對于任意一個對象,可以調用它的任意方法或者獲取其屬性

  • 通俗解析:java 文件需要編譯成. class 文件才能被 jvm 加載使用, 對象的. class 數據在 jvm 里就是 Class;我們如果能拿到這個 Class對象,就能獲取該 Class對應的對象類型,及在該類型聲明的方法和屬性值;還可以根據 Class創建相應的類型對象,通過 Field,Method 反過來操作對象

  • java 相關類介紹

類名描述
Class代表類的實體,在運行的 Java 應用程序中表示類或者接口
Field類的成員變量(成員變量也稱為類的屬性)
Method類的方法
Constructor類的構造方法

獲取 Class 的三種方法

  • 1 通過已知的類型獲取 class
//?根據Example?獲取Class?=》Example.class
public?Class?getExample(){
????Class?clazz?=?Example.class;return?clazz;
}
  • 2 通過實例對象獲取 class
public?Class?getExampleByInstance(){
????Example?example?=?new?Example();
????// getClass是Object類里面的方法;《?》?是通配符
????Class?clazz?=?example.getClass();return?(Class)clazz;
}
  • 3 通過 Class.forName 獲取全路徑指定類名的 class
/\*\*?forName0?本地方法,C++實現,jvm調用
?\* 1 className 是個類名? 2 initialize 是否延遲加載? 3 loader 加載器
?\*/
private?static?native?Class?forName0(String?className,?boolean?initialize,
????????ClassLoader?loader,?Class?caller)?throws?ClassNotFoundException;

public?static?Class?forName(String?className)?throws?ClassNotFoundException?{
????????Class?caller?=?Reflection.getCallerClass();
????????return?forName0(className,?true,?ClassLoader.getClassLoader(caller),?caller);
????}
//?兩個forName方法最終都會調用forName0方法去加載class???
public?static?Class?forName(String?name,
????????boolean?initialize,?ClassLoader?loader)?throws?ClassNotFoundException?{
????????....
????????return?forName0(name,?initialize,?loader,?caller);
????}
//?示例:通過java.lang.Integer?
public?Class?getInteger()throws?ClassNotFoundException{
????Class?clazz?=?Class.forName("java.lang.Integer");return?(Class)clazz;
}

JAVA 反射 API

  • Class 常用操作方法
//獲取所有的構造方法?/?private?public
public?Constructor\[\]?getDeclaredConstructors()
//獲取特定的構造方法?/?private?public
public?Constructor?getDeclaredConstructor(Class...?parameterTypes)????
//獲取類的父類
public?native?Class?getSuperclass()????
//獲取類實現的接口
private?Class\[\]?getInterfaces(boolean?cloneArray)??
//獲取在類內定義的內部類或接口
public?Class\[\]?getDeclaredClasses()
//獲取所有的方法
public?Method\[\]?getDeclaredMethods()?throws?SecurityException
//根據方法名和參數獲得特定的方法
public?Method?getDeclaredMethod(String?name,?Class...?parameterTypes)??
//獲取類型的定義的所有屬性
public?Field\[\]?getFields()?throws?SecurityException
//?根據屬性命名獲得特定的Field
public?Field?getField(String?name)?
  • Method 常用的操作方法
//獲得方法的放回類型
public?Class?getReturnType()???
//獲得方法的傳入參數類型
public?Class\[\]?getParameterTypes()???
//obj是實例對象,args是方法,反過來由Method控制對象的方法調用
public?Object?invoke(Object?obj,?Object...?args)
  • Field 常用的操作方法
//屬性與obj相等則返回true
public?boolean?equals(Object?obj)
//獲得obj中對應的屬性值
public?Object?get(Object?obj)
//設置obj中對應屬性值
public?void?set(Object?obj,?Object?value)?
  • Constructor
//根據傳遞的參數創建類的對象:initargs?構造方法參數
public?T?newInstance(Object...?initargs)?
  • 1 根據 class 創建對象
//方式一?clazz.newInstance()
Class?clazz?=?Example.class;
Example?example?=?clazz.newInstance();
//方式二?先獲取再由Constructor:clazz.getConstructors()/getConstructor(...)?
//再由Constructor.newInstance?方法構造對象
-----------------------------------------
public?class?Example?{
????private?int?value;
????public?Example(){?}?//?如果只聲明有參構造函數,clazz.newInstance()會報錯
????public?Example(Integer?value){??this.value??=?value;??}
????static?public?void?main(String\[\]?args)?throws?Exception{
????????Class?clazz?=?Example.class;
????????//根據指定構造函數參數獲取Constructor
????????Constructor?constructor?=?clazz.getConstructor(Integer.class);
????????Example?example?=?constructor.newInstance(100);
????????System.out.println(example.value);
????}
}????
  • 2 由 class 獲取 Field,并操作實例的屬性
public?class?Example?{
????private?int?value?,?count;
????static?public?void?main(String\[\]?args)?throws?Exception{
????????Class?clazz?=?Example.class;
????????//獲取所有的屬性,getField只能獲取public的屬性
????????Field\[\]?fs?=?clazz.getDeclaredFields();
????????//根據名稱獲取指定?Field
????????Field?value?=?clazz.getDeclaredField("value");
????????Example?example?=?clazz.newInstance();
????????//使用反射機制可以打破封裝性,導致了java對象的屬性不安全??
????????value.setAccessible(true);?//setAccessible(true)讓private的參數可賦值操作
????????//由Field反過去設置example的值
????????value.set(example,100);
????????System.out.println(example.value);
????}
}
  • 3 由 class 獲取 Method,并反射調用實例方法
public?class?Example?{
????public?static?void?main(String\[\]?args)?throws?Exception?{
????????Class?clazz?=?Example.class;
????????Example?example?=?clazz.newInstance();
????????Method\[\]?methods?=?clazz.getDeclaredMethods();
????????//getDeclaredMethod和getMethod是:getMethod只能返回public的方法
????????Method?method?=?clazz.getDeclaredMethod("hello",?String.class);
????????method.setAccessible(true);
????????method.invoke(example,?"cscw");
????}
????private?void?hello(String?name)?{?System.out.println(name?+?"?Hello!");?}
}
-----
cscw?Hello!

反射機制應用的場景

  • 1 動態拓展:假設有同一組類是實現相同的接口,并且類的加載方式不限制。當我們需要那種具體類實現的功能時,只需加載. class 文件,并獲取對應的 Class對象。可以由 Class 或者 Constructor 實例化對象 instance;根據接口定義,可以獲取 Class里的某一方法 Method,并配合 instance 反射調用功能方法

  • 2 Spring 的 IOC 就是基于反射機制實現

  • 3 JDK 的動態代理

反射和 JDK 動態代理

  • 在 Java 的 java.lang.reflect 包下提供了一個 Proxy 類和一個 InvocationHandler 接口。通過這個類和接口可以生成 JDK 動態代理類或動態代理對象
public?interface?InvocationHandler?{
?//所有方法都會調用此代理方法
????Object?invoke(Object?var1,?Method?var2,?Object\[\]?var3)?throws?Throwable;
}??
public?class?Proxy?implements?Serializable{
?...
????//根據interfaces和InvocationHandler生成代理對象
????public?static?Object?newProxyInstance(ClassLoader?loader,
??????Class\[\]?interfaces,?InvocationHandler?h)?
????...????

  • JDK 的動態代理由 Proxy 和 InvocationHandler 實現;而被代理對象必須實現一個接口。代理對象由 Proxy 生成,可轉為接口 interface 的實現類對象 OBJ。當調用 OBJ 的方法時,則會觸發 InvocationHandler.invoke,參數依次為「代理對象」「Method 對象」, 和「方法 Method 所需的參數」。在 invoke 方法可以加入拓展的邏輯,如日志記錄操作;「并可以在 invoke 里利用反射的技術調用被代理對象方法」

  • 示例

public?class?ExampleFactory?implements?InvocationHandler{
????private?T?target;?//被代理對象
????public?T?bind(T?obj){
????????target?=?obj;return?(T)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
???????????obj.getClass().getInterfaces(),this);
????}
????/\*\*?Object?o?是代理對象;?o的方法調用?->?ExampleFactory.invoke?
????\*??invoke(...)?->?在invoke方法里面?反射調用代理對象方法+增強邏輯
????\*/
????@Override
????public?Object?invoke(Object?o,?Method?method,?Object\[\]?objects)?throws?Throwable?{
????????//增強邏輯
????????System.out.println("log?start");
????????//反射調用被代理對象方法
????????Object?result?=?method.invoke(target,objects);
????????System.out.println("log?end");return?result;
????}
}
-----------
public?interface?Face?{
????void?hello(String?name);
}
---------
//被代理對象必須實現一個接口,并由接口方法對方提供功能
public?class?Example?implements?Face?{
?public?void?hello(String?name)?{
????????System.out.println(name?+?"?Hello!");
????}
????public?static?void?main(String\[\]?args)??{
???????//ExampleFactory?相當于一個中介人
????????ExampleFactory?factory?=?new?ExampleFactory<>();
????????//example?是代理對象
????????Face?example?=?exampleProxy.bind(new?Example());
????????example.hello("思婷");
????}
}
-----log?start
思婷?Hello!log?end

歡迎指正文中錯誤

總結

以上是生活随笔為你收集整理的java 反射机制_基础篇:深入解析JAVA反射机制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。