欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          java反射機(jī)制詳細(xì)解析(總結(jié)分享)

          本篇文章給大家?guī)砹岁P(guān)于java的相關(guān)知識,其中主要介紹了關(guān)于反射機(jī)制的詳細(xì)解析,包括了反射機(jī)制的概述、class類的理解、創(chuàng)建運(yùn)行時類的對象等等內(nèi)容,下面一起來看一下,希望對大家有幫助。

          java反射機(jī)制詳細(xì)解析(總結(jié)分享)

          推薦學(xué)習(xí):《java視頻教程》

          一、Java反射機(jī)制概述

          1. Java Reflection

          (1)Reflection(反射)是被視為動態(tài)語言的關(guān)鍵,反射機(jī)制允許程序在執(zhí)行期 借助于ReflectionAPI取得任何類的內(nèi)部信息,并能直接操作任意對象的內(nèi) 部屬性及方法。

          (2)加載完類之后,在堆內(nèi)存的方法區(qū)中就產(chǎn)生了一個Class類型的對象(一個類只有一個Class對象),這個對象就包含了完整的類的結(jié)構(gòu)信息。我們可以通過這個對象看到類的結(jié)構(gòu)。這個對象就像一面鏡子,透過這個鏡子看到類的結(jié)構(gòu),所以,我們形象的稱之為:反射。
          java反射機(jī)制詳細(xì)解析(總結(jié)分享)

          2. 動態(tài)語言 vs 靜態(tài)語言

          (1)動態(tài)語言

          是一類在運(yùn)行時可以改變其結(jié)構(gòu)的語言:例如新的函數(shù)、對象、甚至代碼可以 被引進(jìn),已有的函數(shù)可以被刪除或是其他結(jié)構(gòu)上的變化。通俗點(diǎn)說就是在運(yùn)行時代碼可以根據(jù)某些條件改變自身結(jié)構(gòu)。

          主要動態(tài)語言:Object-C、C#、JavaScript、PHP、Python、Erlang。

          (2)靜態(tài)語言

          與動態(tài)語言相對應(yīng)的,運(yùn)行時結(jié)構(gòu)不可變的語言就是靜態(tài)語言。如Java、C、C++。Java不是動態(tài)語言,但Java可以稱之為“準(zhǔn)動態(tài)語言”。即Java有一定的動態(tài)性,我們可以利用反射機(jī)制、字節(jié)碼操作獲得類似動態(tài)語言的特性。 Java的動態(tài)性讓編程的時候更加靈活!

          (3)Java反射機(jī)制研究及應(yīng)用

          Java反射機(jī)制提供的功能

          1. 在運(yùn)行時判斷任意一個對象所屬的類
          2. 在運(yùn)行時構(gòu)造任意一個類的對象
          3. 在運(yùn)行時判斷任意一個類所具有的成員變量和方法
          4. 在運(yùn)行時獲取泛型信息 在運(yùn)行時調(diào)用任意一個對象的成員變量和方法
          5. 在運(yùn)行時處理注解 生成動態(tài)代理

          反射相關(guān)的主要API

          1. java.lang.Class:代表一個類
          2. java.lang.reflect.Method:代表類的方法
          3. java.lang.reflect.Field:代表類的成員變量
          4. java.lang.reflect.Constructor:代表類的構(gòu)造器 ? … …

          二、 Class類的理解

          1. 類的加載過程

          1.1 初步了解

          程序經(jīng)過javac.exe命令以后,會生成一個或多個字節(jié)碼文件(.class結(jié)尾)。
          接著我們使用java.exe命令對某個字節(jié)碼文件進(jìn)行解釋運(yùn)行。相當(dāng)于將某個字節(jié)碼文件加載到內(nèi)存中。此過程就稱為類的加載。加載到內(nèi)存中的類,我們就稱為運(yùn)行時類,此運(yùn)行時類,就作為Class的一個實例。

          換句話說,Class的實例就對應(yīng)著一個運(yùn)行時類。

          加載到內(nèi)存中的運(yùn)行時類,會緩存一定的時間。在此時間之內(nèi),我們可以通過不同的方式來獲取此運(yùn)行時類。

          1.2 類的加載過程圖解

          當(dāng)程序主動使用某個類時,如果該類還未被加載到內(nèi)存中,則系統(tǒng)會通過如下三個步驟來對該類進(jìn)行初始化。

          java反射機(jī)制詳細(xì)解析(總結(jié)分享)

          類的加載:將class文件字節(jié)碼內(nèi)容加載到內(nèi)存中,并將這些靜態(tài)數(shù)據(jù)轉(zhuǎn)換成方法區(qū)的運(yùn)行時數(shù)據(jù)結(jié)構(gòu),然后生成一個代表這個類的java.lang.Class對象,作為方法區(qū)中類數(shù)據(jù)的訪問入口(即引用地址)。所有需要訪問和使用類數(shù)據(jù)只能通過這個Class對象。這個加載的過程需要類加載器參與。

          類的鏈接:將Java類的二進(jìn)制代碼合并到JVM的運(yùn)行狀態(tài)之中的過程。
          ● 驗證:確保加載的類信息符合JVM規(guī)范,例如:以cafe開頭,沒有安全方面的問題
          ● 準(zhǔn)備:正式為類變量(static)分配內(nèi)存并設(shè)置類變量默認(rèn)初始值的階段,這些內(nèi)存 都將在方法區(qū)中進(jìn)行分配。
          ● 解析:虛擬機(jī)常量池內(nèi)的符號引用(常量名)替換為直接引用(地址)的過程。

          類的初始化:
          ● 執(zhí)行類構(gòu)造器【clinit】()方法的過程。類構(gòu)造器【clinit】()方法是由編譯期自動收集類中 所有類變量的賦值動作和靜態(tài)代碼塊中的語句合并產(chǎn)生的。(類構(gòu)造器是構(gòu)造類信 息的,不是構(gòu)造該類對象的構(gòu)造器)。
          ● 當(dāng)初始化一個類的時候,如果發(fā)現(xiàn)其父類還沒有進(jìn)行初始化,則需要先觸發(fā)其父類 的初始化。
          ● 虛擬機(jī)會保證一個類的()方法在多線程環(huán)境中被正確加鎖和同步。

          public class ClassLoadingTest { public static void main(String[] args) { System.out.println(A.m); } } class A { static { m = 300; } static int m = 100; } //第二步:鏈接結(jié)束后m=0 //第三步:初始化后,m的值由<clinit>()方法執(zhí)行決定 // 這個A的類構(gòu)造器<clinit>()方法由類變量的賦值和靜態(tài)代碼塊中的語句按照順序合并產(chǎn)生,類似于 // <clinit>(){ // m = 300; // m = 100; // }

          1.3 了解:什么時候會發(fā)生類初始化?

          類的主動引用(一定會發(fā)生類的初始化)

          1. 當(dāng)虛擬機(jī)啟動,先初始化main方法所在的類
          2. new一個類的對象
          3. 調(diào)用類的靜態(tài)成員(除了final常量)和靜態(tài)方法
          4. 使用java.lang.reflect包的方法對類進(jìn)行反射調(diào)用
          5. 當(dāng)初始化一個類,如果其父類沒有被初始化,則先會初始化它的父類

          類的被動引用(不會發(fā)生類的初始化)

          1. 當(dāng)訪問一個靜態(tài)域時,只有真正聲明這個域的類才會被初始化
          2. 當(dāng)通過子類引用父類的靜態(tài)變量,不會導(dǎo)致子類初始化
          3. 通過數(shù)組定義類引用,不會觸發(fā)此類的初始化
          4. 引用常量不會觸發(fā)此類的初始化(常量在鏈接階段就存入調(diào)用類的常量池中了)

          1.4 類加載器的作用

          類加載的作用:將class文件字節(jié)碼內(nèi)容加載到內(nèi)存中,并將這些靜態(tài)數(shù)據(jù)轉(zhuǎn)換成方法區(qū)的運(yùn)行時數(shù)據(jù)結(jié)構(gòu),然后在堆中生成一個代表這個類的java.lang.Class對象,作為 方法區(qū)中類數(shù)據(jù)的訪問入口。
          類緩存:標(biāo)準(zhǔn)的JavaSE類加載器可以按要求查找類,但一旦某個類被加載到類加載器 中,它將維持加載(緩存)一段時間。不過JVM垃圾回收機(jī)制可以回收這些Class對象。

          java反射機(jī)制詳細(xì)解析(總結(jié)分享)

          1.5 JVM中不同類型的類的加載器

          java反射機(jī)制詳細(xì)解析(總結(jié)分享)

          1.6 代碼演示

          不同類型的類的加載器:

           @Test     public void test1(){         //對于自定義類,使用系統(tǒng)類加載器進(jìn)行加載         ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();         System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2:系統(tǒng)類加載器         //調(diào)用系統(tǒng)類加載器的getParent():獲取擴(kuò)展類加載器         ClassLoader classLoader1 = classLoader.getParent();         System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@279f2327:擴(kuò)展類加載器         //調(diào)用擴(kuò)展類加載器的getParent():無法獲取引導(dǎo)類加載器         //引導(dǎo)類加載器主要負(fù)責(zé)加載java的核心類庫,無法加載自定義類的。         ClassLoader classLoader2 = classLoader1.getParent();         System.out.println(classLoader2);//null          ClassLoader classLoader3 = String.class.getClassLoader();         System.out.println(classLoader3);//null      }

          使用系統(tǒng)類加載器讀取Properties配置文件。

           /*     Properties:用來讀取配置文件。       */     @Test     public void test2() throws Exception {          Properties pros =  new Properties();         //此時的文件默認(rèn)在當(dāng)前的module下。         //讀取配置文件的方式一://        FileInputStream fis = new FileInputStream("jdbc.properties");//        FileInputStream fis = new FileInputStream("src\jdbc1.properties");//        pros.load(fis);          //讀取配置文件的方式二:使用ClassLoader         //配置文件默認(rèn)識別為:當(dāng)前module的src下         ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();         InputStream is = classLoader.getResourceAsStream("jdbc1.properties");         pros.load(is);           String user = pros.getProperty("user");         String password = pros.getProperty("password");         System.out.println("user = " + user + ",password = " + password);     }}

          2. 何為Class類?

          Class類在Object類中定義了以下的方法,此方法將被所有子類繼承:

          public final Class getClass()

          以上的方法返回值的類型是一個Class類,此類是Java反射的源頭,實際上所謂反射從程序的運(yùn)行結(jié)果來看也很好理解,即:可以通過對象反射求出類的名稱。

          java反射機(jī)制詳細(xì)解析(總結(jié)分享)

          對象照鏡子后可以得到的信息:某個類的屬性、方法和構(gòu)造器、某個類到底實現(xiàn)了哪些接口。對于每個類而言,JRE 都為其保留一個不變的Class類型的對象。
          一個 Class對象包含了特定某個結(jié)構(gòu)(class/interface/enum/annotation/primitivetype/void/[])的有關(guān)信息。

          Class本身也是一個類

          Class 對象只能由系統(tǒng)建立對象

          一個加載的類在 JVM中只會有一個Class實例

          一個Class對象對應(yīng)的是一個加載到JVM中的一個.class文件

          每個類的實例都會記得自己是由哪個Class 實例所生成

          通過Class可以完整地得到一個類中的所有被加載的結(jié)構(gòu)

          Class類是Reflection的根源,針對任何你想動態(tài)加載、運(yùn)行的類,唯有先獲得相應(yīng)的

          3. Class類的常用方法方法

          方法名 功能說明
          static Class forName(String name) 返回指定類名 nameClass 對象
          Object newInstance() 調(diào)用缺省構(gòu)造函數(shù),返回該Class對象的一個實例
          getName() 返回此Class對象所表示的實體(類、接口、數(shù)組類、基本類型或void)名稱
          Class getSuperClass() 返回當(dāng)前Class對象的父類的Class對象
          Class [] getInterfaces() 獲取當(dāng)前Class對象的接口
          ClassLoader getClassLoader() 返回該類的類加載器
          Class getSuperclass() 返回表示此Class所表示的實體的超類的Class
          Constructor[] getConstructors() 返回一個包含某些Constructor對象的數(shù)組
          Field[] getDeclaredFields() 返回Field對象的一個數(shù)組
          Method getMethod(String name,Class … paramTypes) 返回一個Method對象,此對象的形參類型為paramType

          3. 哪些類型可以有Class對象?

          (1)class: 外部類,成員(成員內(nèi)部類,靜態(tài)內(nèi)部類),局部內(nèi)部類,匿名內(nèi)部類
          (2)interface:接口
          (3)[]:數(shù)組
          (4)enum:枚舉
          (5)annotation:注解@interface
          (6)primitive type:基本數(shù)據(jù)類型
          (7)void

          三、獲取Class類實例的四種方法

          1. 調(diào)用運(yùn)行時類的屬性:.class

          前提:若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠, 程序性能最高
          示例: Class clazz1 = String.class;

          2. 通過運(yùn)行時類的對象,調(diào)用getClass()

          前提:已知某個類的實例,調(diào)用該實例的getClass()方法獲取Class對象
          示例:Class clazz = “www.atguigu.com”.getClass();

          3.調(diào)用Class的靜態(tài)方法:forName(String classPath)

          前提:已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態(tài)方法forName() 獲取,可能拋出ClassNotFoundException
          示例: Class clazz = Class.forName(“java.lang.String”);

          4. 使用類的加載器:ClassLoader

          示例:
          ClassLoader cl = this.getClass().getClassLoader();
          Class clazz4 = cl.loadClass(“類的全類名”);

          5. 代碼演示

          @Testpublic void test1() throws ClassNotFoundException {             //方式一:調(diào)用運(yùn)行時類的屬性:.class             Class clazz1 = Person.class;             System.out.println(clazz1);//class com.jiaying.java1.Person             //方式二:通過運(yùn)行時類的對象,調(diào)用getClass()             Person p1 = new Person();             Class clazz2 = p1.getClass();             System.out.println(clazz2);//class com.jiaying.java1.Person              //方式三:調(diào)用Class的靜態(tài)方法:forName(String classPath)             Class clazz3 = Class.forName("com.jiaying.java1.Person");             Class clazz5 = Class.forName("java.lang.String");             System.out.println(clazz3);//class com.jiaying.java1.Person             System.out.println(clazz5);//class java.lang.String              System.out.println(clazz1 == clazz2);//true             System.out.println(clazz1 == clazz3);//true              //方式四:使用類的加載器:ClassLoader  (了解)             ClassLoader classLoader = ReflectionTest.class.getClassLoader();             Class clazz4 = classLoader.loadClass("com.jiaying.java1.Person");             System.out.println(clazz4);//class com.jiaying.java1.Person             System.out.println(clazz1 == clazz4);//true}

          四、 創(chuàng)建運(yùn)行時類的對象

          1. 引入

          有了Class對象,能做什么?

          創(chuàng)建類的對象:調(diào)用Class對象的newInstance()方法
          要求:

          1. 類必須有一個無參數(shù)的構(gòu)造器。
          2. 類的構(gòu)造器的訪問權(quán)限需要足夠。

          難道沒有無參的構(gòu)造器就不能創(chuàng)建對象了嗎?
          不是!只要在操作的時候明確的調(diào)用類中的構(gòu)造器,并將參數(shù)傳遞進(jìn)去之后,才可以實例化操作。
          步驟如下:

          1. 通過Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參類型的構(gòu)造器
          2. 向構(gòu)造器的形參中傳遞一個對象數(shù)組進(jìn)去,里面包含了構(gòu)造器中所需的各個參數(shù)。
          3. 通過Constructor實例化對象。

          2. 語法步驟

          (1)根據(jù)全類名獲取對應(yīng)的Class對象

          String name = “atguigu.java.Person";Class clazz = null;clazz = Class.forName(name);

          (2)調(diào)用指定參數(shù)結(jié)構(gòu)的構(gòu)造器,生成Constructor的實例

          Constructor con = clazz.getConstructor(String.class,Integer.class);

          (3)通過Constructor的實例創(chuàng)建對應(yīng)類的對象,并初始化類屬性

          Person p2 = (Person) con.newInstance("Peter",20);System.out.println(p2);

          3. 代碼演示

           @Test     public void test1() throws IllegalAccessException, InstantiationException {          Class<Person> clazz = Person.class;         /*         newInstance():調(diào)用此方法,創(chuàng)建對應(yīng)的運(yùn)行時類的對象。內(nèi)部調(diào)用了運(yùn)行時類的空參的構(gòu)造器。          要想此方法正常的創(chuàng)建運(yùn)行時類的對象,要求:         1.運(yùn)行時類必須提供空參的構(gòu)造器         2.空參的構(gòu)造器的訪問權(quán)限得夠。通常,設(shè)置為public。           在javabean中要求提供一個public的空參構(gòu)造器。原因:         1.便于通過反射,創(chuàng)建運(yùn)行時類的對象         2.便于子類繼承此運(yùn)行時類時,默認(rèn)調(diào)用super()時,保證父類有此構(gòu)造器           */         Person obj = clazz.newInstance();         System.out.println(obj);      }

          4. 體會反射的動態(tài)性

          //體會反射的動態(tài)性     @Test     public void test2(){          for(int i = 0;i < 100;i++){             int num = new Random().nextInt(3);//0,1,2             String classPath = "";             switch(num){                 case 0:                     classPath = "java.util.Date";                     break;                 case 1:                     classPath = "java.lang.Object";                     break;                 case 2:                     classPath = "com.atguigu.java.Person";                     break;             }              try {                 Object obj = getInstance(classPath);                 System.out.println(obj);             } catch (Exception e) {                 e.printStackTrace();             }         }     }      /*     創(chuàng)建一個指定類的對象。     classPath:指定類的全類名      */     public Object getInstance(String classPath) throws Exception {        Class clazz =  Class.forName(classPath);        return clazz.newInstance();     }}

          五、獲取運(yùn)行時類的完整結(jié)構(gòu)

          提供具有豐富內(nèi)容的Person

          //接口public interface MyInterface {     void info();}//注解@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotation {     String value() default "hello";}//父類public class Creature<T> implements Serializable {     private char gender;     public double weight;      private void breath(){         System.out.println("生物呼吸");     }      public void eat(){         System.out.println("生物吃東西");     }}//Person類@MyAnnotation(value="hi")public class Person extends Creature<String> implements Comparable<String>,MyInterface{      private String name;     int age;     public int id;      public Person(){}      @MyAnnotation(value="abc")     private Person(String name){         this.name = name;     }       Person(String name,int age){         this.name = name;         this.age = age;     }     @MyAnnotation     private String show(String nation){         System.out.println("我的國籍是:" + nation);         return nation;     }      public String display(String interests,int age) throws NullPointerException,ClassCastException{         return interests + age;     }       @Override     public void info() {         System.out.println("我是一個人");     }      @Override     public int compareTo(String o) {         return 0;     }      private static void showDesc(){         System.out.println("我是一個可愛的人");     }      @Override     public String toString() {         return "Person{" +                 "name='" + name + ''' +                 ", age=" + age +                 ", id=" + id +                 '}';     }}

          1. 獲取當(dāng)前運(yùn)行時類的屬性結(jié)構(gòu)

          方法 作用
          public Field[] getFields() 返回此Class對象所表示的類或接口的publicField
          public Field[] getDeclaredFields() 返回此Class對象所表示的類或接口的全部Field
          • Field方法中:
          方法 作用
          public int getModifiers() 以整數(shù)形式返回此Field的修飾符
          public Class<?> getType() 得到Field的屬性類型
          public String getName() 返回Field的名稱
              @Test     public void test1(){          Class clazz = Person.class;          //獲取屬性結(jié)構(gòu)         //getFields():獲取當(dāng)前運(yùn)行時類及其父類中聲明為public訪問權(quán)限的屬性         Field[] fields = clazz.getFields();         for(Field f : fields){             System.out.println(f);         }         System.out.println();          //getDeclaredFields():獲取當(dāng)前運(yùn)行時類中聲明的所有屬性。(不包含父類中聲明的屬性)         Field[] declaredFields = clazz.getDeclaredFields();         for(Field f : declaredFields){             System.out.println(f);         }     }      //權(quán)限修飾符  數(shù)據(jù)類型 變量名     @Test     public void test2(){         Class clazz = Person.class;         Field[] declaredFields = clazz.getDeclaredFields();         for(Field f : declaredFields){             //1.權(quán)限修飾符             int modifier = f.getModifiers();             System.out.print(Modifier.toString(modifier) + "t");              //2.數(shù)據(jù)類型             Class type = f.getType();             System.out.print(type.getName() + "t");              //3.變量名             String fName = f.getName();             System.out.print(fName);              System.out.println();         }     }}

          2. 獲取當(dāng)前運(yùn)行時類的方法結(jié)構(gòu)

          方法 作用
          public Method[] getMethods() 返回此Class對象所表示的類或接口的public的方法
          public Method[] getDeclaredMethods() 返回此Class對象所表示的類或接口的全部方法
          • Method類中:
          方法 作用
          public Class<?> getReturnType() 取得全部的返回值
          public Class<?>[] getParameterTypes() 取得全部的參數(shù)
          public int getModifiers() 取得修飾符
          public Class<?>[] getExceptionTypes() 取得異常信息
              @Test     public void test1(){          Class clazz = Person.class;          //getMethods():獲取當(dāng)前運(yùn)行時類及其所有父類中聲明為public權(quán)限的方法         Method[] methods = clazz.getMethods();         for(Method m : methods){             System.out.println(m);         }         System.out.println();         //getDeclaredMethods():獲取當(dāng)前運(yùn)行時類中聲明的所有方法。(不包含父類中聲明的方法)         Method[] declaredMethods = clazz.getDeclaredMethods();         for(Method m : declaredMethods){             System.out.println(m);         }     }   /*     @Xxxx     權(quán)限修飾符  返回值類型  方法名(參數(shù)類型1 形參名1,...) throws XxxException{}      */     @Test     public void test2(){         Class clazz = Person.class;         Method[] declaredMethods = clazz.getDeclaredMethods();         for(Method m : declaredMethods){             //1.獲取方法聲明的注解             Annotation[] annos = m.getAnnotations();             for(Annotation a : annos){                 System.out.println(a);             }              //2.權(quán)限修飾符             System.out.print(Modifier.toString(m.getModifiers()) + "t");              //3.返回值類型             System.out.print(m.getReturnType().getName() + "t");              //4.方法名             System.out.print(m.getName());             System.out.print("(");             //5.形參列表             Class[] parameterTypes = m.getParameterTypes();             if(!(parameterTypes == null && parameterTypes.length == 0)){                 for(int i = 0;i < parameterTypes.length;i++){                      if(i == parameterTypes.length - 1){                         System.out.print(parameterTypes[i].getName() + " args_" + i);                         break;                     }                      System.out.print(parameterTypes[i].getName() + " args_" + i + ",");                 }             }              System.out.print(")");              //6.拋出的異常             Class[] exceptionTypes = m.getExceptionTypes();             if(exceptionTypes.length > 0){                 System.out.print("throws ");                 for(int i = 0;i < exceptionTypes.length;i++){                     if(i == exceptionTypes.length - 1){                         System.out.print(exceptionTypes[i].getName());                         break;                     }                      System.out.print(exceptionTypes[i].getName() + ",");                 }             }               System.out.println();         }        }}

          3. 獲取當(dāng)前運(yùn)行時類的構(gòu)造器結(jié)構(gòu)

          方法 作用
          public Constructor<T>[] getConstructors() 返回此 Class 對象所表示的類的所有public構(gòu)造方法。
          public Constructor<T>[] getDeclaredConstructors() 返回此 Class 對象表示的類聲明的所有構(gòu)造方法。
          • Constructor類中:
          方法 作用
          public int getModifiers() 取得修飾符
          public String getName() 取得方法名稱
          public Class<?>[] getParameterTypes() 取得參數(shù)的類型
          /*     獲取構(gòu)造器結(jié)構(gòu)       */     @Test     public void test1(){          Class clazz = Person.class;         //getConstructors():獲取當(dāng)前運(yùn)行時類中聲明為public的構(gòu)造器         Constructor[] constructors = clazz.getConstructors();         for(Constructor c : constructors){             System.out.println(c);         }          System.out.println();         //getDeclaredConstructors():獲取當(dāng)前運(yùn)行時類中聲明的所有的構(gòu)造器         Constructor[] declaredConstructors = clazz.getDeclaredConstructors();         for(Constructor c : declaredConstructors){             System.out.println(c);         }      }  /*     獲取運(yùn)行時類的父類       */     @Test     public void test2(){         Class clazz = Person.class;          Class superclass = clazz.getSuperclass();         System.out.println(superclass);     }      /*     獲取運(yùn)行時類的帶泛型的父類       */     @Test     public void test3(){         Class clazz = Person.class;          Type genericSuperclass = clazz.getGenericSuperclass();         System.out.println(genericSuperclass);     }      /*     獲取運(yùn)行時類的帶泛型的父類的泛型       代碼:邏輯性代碼  vs 功能性代碼      */     @Test     public void test4(){         Class clazz = Person.class;          Type genericSuperclass = clazz.getGenericSuperclass();         ParameterizedType paramType = (ParameterizedType) genericSuperclass;         //獲取泛型類型         Type[] actualTypeArguments = paramType.getActualTypeArguments();//        System.out.println(actualTypeArguments[0].getTypeName());         System.out.println(((Class)actualTypeArguments[0]).getName());     }/*     獲取運(yùn)行時類實現(xiàn)的接口      */     @Test     public void test5(){         Class clazz = Person.class;          Class[] interfaces = clazz.getInterfaces();         for(Class c : interfaces){             System.out.println(c);         }          System.out.println();         //獲取運(yùn)行時類的父類實現(xiàn)的接口         Class[] interfaces1 = clazz.getSuperclass().getInterfaces();         for(Class c : interfaces1){             System.out.println(c);         }      }     /*         獲取運(yùn)行時類所在的包       */     @Test     public void test6(){         Class clazz = Person.class;          Package pack = clazz.getPackage();         System.out.println(pack);     }      /*         獲取運(yùn)行時類聲明的注解       */     @Test     public void test7(){         Class clazz = Person.class;          Annotation[] annotations = clazz.getAnnotations();         for(Annotation annos : annotations){             System.out.println(annos);         }     }}

          六、調(diào)用運(yùn)行時類的指定結(jié)構(gòu)

          關(guān)于setAccessible方法的使用

          MethodField、Constructor對象都有setAccessible()方法。

          setAccessible啟動和禁用訪問安全檢查的開關(guān)。

          參數(shù)值為true則指示反射的對象在使用時應(yīng)該取消Java語言訪問檢查。

          提高反射的效率。如果代碼中必須用反射,而該句代碼需要頻繁的被 調(diào)用,那么請設(shè)置為true,使得原本無法訪問的私有成員也可以訪問,參數(shù)值為false則指示反射的對象應(yīng)該實施Java語言訪問檢查。

          1. 調(diào)用運(yùn)行時類中指定的屬性

          在反射機(jī)制中,可以直接通過Field類操作類中的屬性,通過Field類提供的set()get()方法就可以完成設(shè)置和取得屬性內(nèi)容的操作。

          方法 作用
          public Field getField(String name) 返回此Class對象表示的類或接口的指定的publicField
          public Field getDeclaredField(String name) 返回此Class對象表示的類或接口的指定的Field

          在Field中:

          方法 作用
          public Object get(Object obj) 取得指定對象obj上此Field的屬性內(nèi)容
          public void set(Object obj,Object value) 設(shè)置指定對象obj上此Field的屬性內(nèi)容

          代碼演示:

          public class ReflectionTest {     @Test     public void testField() throws Exception {         Class clazz = Person.class;          //創(chuàng)建運(yùn)行時類的對象         Person p = (Person) clazz.newInstance();           //獲取指定的屬性:要求運(yùn)行時類中屬性聲明為public         //通常不采用此方法         Field id = clazz.getField("id");          /*         設(shè)置當(dāng)前屬性的值          set():參數(shù)1:指明設(shè)置哪個對象的屬性   參數(shù)2:將此屬性值設(shè)置為多少          */          id.set(p,1001);          /*         獲取當(dāng)前屬性的值         get():參數(shù)1:獲取哪個對象的當(dāng)前屬性值          */         int pId = (int) id.get(p);         System.out.println(pId);       }     /*     如何操作運(yùn)行時類中的指定的屬性 -- 需要掌握      */     @Test     public void testField1() throws Exception {         Class clazz = Person.class;          //創(chuàng)建運(yùn)行時類的對象         Person p = (Person) clazz.newInstance();          //1. getDeclaredField(String fieldName):獲取運(yùn)行時類中指定變量名的屬性         Field name = clazz.getDeclaredField("name");          //2.保證當(dāng)前屬性是可訪問的         name.setAccessible(true);         //3.獲取、設(shè)置指定對象的此屬性值         name.set(p,"Tom");          System.out.println(name.get(p));     }

          2. 調(diào)用運(yùn)行時類中的指定的方法

          通過反射,調(diào)用類中的方法,通過Method類完成。步驟:

          1. 通過Class類的getMethod(String name,Class…parameterTypes)方法取得 一個Method對象,并設(shè)置此方法操作時所需要的參數(shù)類型。
          2. 之后使用Object invoke(Object obj, Object[] args)進(jìn)行調(diào)用,并向方法中 傳遞要設(shè)置的obj對象的參數(shù)信息。

          java反射機(jī)制詳細(xì)解析(總結(jié)分享)

          Object invoke(Object obj, Object … args)
          說明:
          Object 對應(yīng)原方法的返回值,若原方法無返回值,此時返回null

          若原方法若為靜態(tài)方法,此時形參Object obj可為null

          若原方法形參列表為空,則Object[] argsnull
          若原方法聲明為private,則需要在調(diào)用此invoke()方法前,顯式調(diào)用 方法對象的setAccessible(true)方法,將可訪問private的方法。

          代碼演示:

           /*     如何操作運(yùn)行時類中的指定的方法 -- 需要掌握      */     @Test     public void testMethod() throws Exception {          Class clazz = Person.class;          //創(chuàng)建運(yùn)行時類的對象         Person p = (Person) clazz.newInstance();          /*         1.獲取指定的某個方法         getDeclaredMethod():參數(shù)1 :指明獲取的方法的名稱  參數(shù)2:指明獲取的方法的形參列表          */         Method show = clazz.getDeclaredMethod("show", String.class);         //2.保證當(dāng)前方法是可訪問的         show.setAccessible(true);          /*         3. 調(diào)用方法的invoke():參數(shù)1:方法的調(diào)用者  參數(shù)2:給方法形參賦值的實參         invoke()的返回值即為對應(yīng)類中調(diào)用的方法的返回值。          */         Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");         System.out.println(returnValue);          System.out.println("*************如何調(diào)用靜態(tài)方法*****************");          // private static void showDesc()          Method showDesc = clazz.getDeclaredMethod("showDesc");         showDesc.setAccessible(true);         //如果調(diào)用的運(yùn)行時類中的方法沒有返回值,則此invoke()返回null//        Object returnVal = showDesc.invoke(null);         Object returnVal = showDesc.invoke(Person.class);         System.out.println(returnVal);//null      }

          3. 調(diào)用運(yùn)行時類中的指定的構(gòu)造器

          代碼演示:

            /*     如何調(diào)用運(yùn)行時類中的指定的構(gòu)造器      */     @Test     public void testConstructor() throws Exception {         Class clazz = Person.class;          //private Person(String name)         /*         1.獲取指定的構(gòu)造器         getDeclaredConstructor():參數(shù):指明構(gòu)造器的參數(shù)列表          */          Constructor constructor = clazz.getDeclaredConstructor(String.class);          //2.保證此構(gòu)造器是可訪問的         constructor.setAccessible(true);          //3.調(diào)用此構(gòu)造器創(chuàng)建運(yùn)行時類的對象         Person per = (Person) constructor.newInstance("Tom");         System.out.println(per);      }}

          推薦學(xué)習(xí):《java視頻教程》

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號