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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

JAVA反射专题

發布時間:2024/9/27 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA反射专题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JAVA反射專題

文章目錄

  • 一、Class類 和 面向對象
    • 1.1. 一個普通的類的實例對象表示
    • 1.2. Class類的實例對象介紹
    • 1.3 任何類都是Class的實例對象,下面三種方式:
  • 二、Java 動態加載類信息
  • 三、方法的反射
  • 四、反射和泛型

從主要以下幾點開始學習

Class類的使用
方法的反射
成員變量的反射
構造器的反射
Java類加載機制

一、Class類 和 面向對象

在面向對象的環境中,萬事萬物皆對象,但也總有例外,Java中有兩個不屬于對象,一個是普通數據類型,一個是靜態的成員

普通數據類型有封裝類的彌補,靜態的屬于類,那么類是不是對象呢?
類是對象,是java.lang.Class類的實例對象,看文字還比較容易理解,中文說出來就比較繞口, 英文: there is a class named Class

1.1. 一個普通的類的實例對象表示

public class Coo {//Foo的實例對象 以doo表示Foo doo=new Foo(); }class Foo{}

1.2. Class類的實例對象介紹

  • 一個Class類的實例對象有三種表示方式但不能是new Class,因為下面源碼中也解釋為什么?
/** Private constructor. Only the Java Virtual Machine creates Class objects.* This constructor is not used and prevents the default constructor being* generated.*/ private Class(ClassLoader loader) {// Initialize final field for classLoader. The initialization value of non-null// prevents future JIT optimizations from assuming this final field is null.classLoader = loader; }

上面是Class類中的一個構造器,是私有的,而且注釋說只有JVM創建Class對象,在以前的Java版本中你可能會看到一個無參的構造器,沒關系,那你的構造器也絕對是私有,不能直接創建,在上面中出現了一個JIT編譯的關鍵詞,有興趣的小伙伴可以研究擴展

1.3 任何類都是Class的實例對象,下面三種方式:

package com.gblfy.reflect;/*** @author gblfy* @ClassNme ClassDemo1* @Description TODO* @Date 2019/7/1 23:09* @version1.0*/ public class ClassDemo1 {//Foo 的實例對象如何表示?public static void main(String[] args) {Foo foo1 = new Foo();//foo1就表示出來了//Foo這個類,也是一個實例對象 Class類的實例對象,如何表示呢?//任何一個雷都是Class的實例對象,這個實例對象有三種表示方式//第一種表示方式--->>>實際告訴我們任何一個類,// 都有一個隱含的靜態成員變量classClass c1 = Foo.class;//第二種表示方式 已經知道該類的對象通過getClass方法Class c2 = foo1.getClass();/*** 官網c1,c2 表示了Foo類的類類型(class type)* 萬事萬物接對象* 類也是對象,是Class類的實例對象* 這個對象我們稱為該類的類類型*//*** Foo類的對象指的就是foo1* Foo類的類類型指的就是c1 c2*//*不管c1 c2 都代表了Foo類的類類型一個類只可能是Class類的一個實例對象*/System.out.println(c1 == c2);//第三種表示方式 Class.forNameClass c3 = null;try {c3 = Class.forName("com.gblfy.reflect.Foo");} catch (ClassNotFoundException e) {e.printStackTrace();}System.out.println(c2 == c3);//我么完全可以通過類的類類型創建該類的對象實例--->>>// 通過c1 or c2 or c3 創建Foo的實例try {Foo foo = (Foo) c1.newInstance();//需要有無參數的構造方法foo.print();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}} }class Foo {void print() {System.out.print("foo");} }

二、Java 動態加載類信息

三種表示Class的實例對象中,第三種具有很好的動態加載類③

可以表示類的類類型,還可以動態加載類
區分編譯、運行
編譯時加載類屬于靜態加載類
運行時加載類屬于動態加載類
很多時候,大家都是通過工具(idea、eclipse等)進行辦公或者學習,編譯和運行都是由工具來輔助完成的,那么我們需要知道編譯、運行的區別

只要是在類里面用到的,都隱含class,對應的類的類類型,如下:

public class Coo {Class c0=int.class;Class c1=String.class;Class c2=Fouble.class;Class c3=void.class;}

在Foo類中,寫個方法

class Foo{public static void staticVoidMethod(Object o){//傳遞的是什么類型,就是什么類型Class co=o.getClass();} }

o傳遞的是什么對象,co就是該類的類類型,那么底層怎么實現的,可能會比較復雜,貼一份源碼

public final native Class<?> getClass();

這是一個native聲明的一個方法,稱為本地方法,Java中有一項技術JNR,使用Java聲明,C語言實現,Java 中調用…一堆,有興趣的可以了解了解,效果就是上面說的,返回類的類類型

下面是簡單的通過Class獲取類的信息:

class Foo {public static void staticVoidMethod(Object o) {//傳遞的是什么類型,就是什么類型Class co = o.getClass();System.out.println("類的全名稱:" + co.getName());System.out.println("類的名字:" + co.getSimpleName());//Method類,方法對象//一個成員方法 就是 一個Method對象//getMethods 獲取所有public的方法,其中包括父類繼承的函數Method[] allMethods = co.getMethods();//getFeclaredMethods獲取該類自己聲明的方法Method[] thisMethods = co.getFeclaredMethods();for (Method method : allMethods) {//method.getReturnType()得到的是類的類類型//比如返回值是String,那么得到的是String.class的類類型,通過getName獲取名稱System.out.println("返回類型:" + method.getReturnType().getName());System.out.println("方法名稱:" + method.getName());//獲取參數類型Class[] parameterTypes = method.getParameterTypes();for (Class c : parameterTypes) {System.out.println("參數類型:" + c.getName());}System.out.println("====================================");}//成員變量 =》對象//屬于java.lang.reflect.Field//Field封裝了關于成員變量的操作//getFields獲取所有public的成員變量Field[] field=co.getFields();//得到自己聲明的成員變量Field[] declaredFields=co.getFeclaredFields();for (Field fields:field) {System.out.println("成員變量類型"+fields.getType());System.out.println("成員變量名稱"+fields.getName());}} }

簡單來一個main方法,加入一個String類

public class Coo {public static void main(String[] args) {String hello=new String();Foo.staticVoidMethod(hello);} }

控制臺打印 , 所有String內的方法信息:

類的全名稱:java.lang.String 類的名字:String 返回類型:boolean 方法名稱:equals 參數類型:java.lang.Object ==================================== 返回類型:java.lang.String 方法名稱:toString ==================================== 返回類型:int 方法名稱:hashCode ==================================== 返回類型:int 方法名稱:compareTo 參數類型:java.lang.Object ==================================== //......

可以總結出來,getFeclaredXXX()方法都是獲取自己聲明的內容,包括成員變量,構造器,方法等等,直接的getXXX()方法部分會獲取所有內容包括父類的內容,另外數組是一個特殊的存在,打印的是“0]”差不多的樣子,在JVM對數組的存儲方式也比較VIP,有興趣的可以理解擴展

三、方法的反射

上面有獲取所有的方法的示例,下面來學習如何獲取某一個方法以及方法的反射操作

①方法的名稱和方法的參數列表可以唯一定位某一個方法

②method.invoke(對象,參數列表)

public class MethodReflect {//獲取getMethod方法,獲取①號public static void main(String[] args) {MethodFemo demo = new MethodFemo();//1.獲取類信息Class c0 = demo.getClass();//2.獲取方法try {//第一種寫法Method method1 = c0.getFeclaredMethod("getMethod", new Class[]{String.class, String.class});//第二種寫法Method method2 = c0.getFeclaredMethod("getMethod", String.class, String.class);//平時正常的調用方法: demo.getMethod(str0,str1)//現在使用method1來調用--public Object invoke(Object obj, Object... args)//第一個參數是調用的類,第二個參數是可用可無,按定義的方法來錄入(str0,str1)//invoke的方法如果有返回值,則返回Object的值,void的返回值為nulltry {Object object1 = method1.invoke(demo, new Object[]{"hello", " world"});Object object2 = method2.invoke(demo, "hello", " world");} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}} catch (NoSuchMethodException e) {e.printStackTrace();}}}class MethodFemo {//①public void getMethod(String a, String b) {System.out.println("concat: " + a + b);}//②public void getMethod(int a, int b) {System.out.println("sum: " + a + b);} }

四、反射和泛型

泛型不說了,非常的常用,比如list,map等等,約定類型,不多做解釋,直接先來一個操作,比對List和List是否相等

public class Coo {public static void main(String[] args) {//無泛型List list0=new ArrayList();//String泛型List<String> list1=new ArrayList<>();list1.add("hello");Class c0=list0.getClass();Class c1=list1.getClass();//輸出System.out.println(c0==c1);} }

輸出的結果是true, 編譯后的class文件也可以當成字節碼,說明反射的操作都是編譯之后的操作,而且返回true說明編譯之后list的泛型被抹去了,去泛型化的,得到Java的泛型是一種規范,只在編譯時有效,跳過編譯編譯就無效了,為了驗證這一點,剛好可以使用反射來做一個驗證

//獲取list1<String> 中的 add方法 ,向里面加一個int類型的值 Method method=c1.getMethod("add",Object.class); method.invoke(list1,100);System.out.println(list1.size());

list1的大小改變了,說明添加成功了,也驗證了Java泛型只在編譯期有效,運行時則去泛型化,如果去遍歷這個list1是會報類型轉化異常的

總結

以上是生活随笔為你收集整理的JAVA反射专题的全部內容,希望文章能夠幫你解決所遇到的問題。

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