中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java反射機制的概念是什么及怎么用

發布時間:2022-05-18 09:45:21 來源:億速云 閱讀:166 作者:zzz 欄目:編程語言

今天小編給大家分享一下java反射機制的概念是什么及怎么用的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

java反射機制的概念是什么及怎么用

一、Java反射機制概述

1. Java Reflection

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

(2)加載完類之后,在堆內存的方法區中就產生了一個Class類型的對象(一個類只有一個Class對象),這個對象就包含了完整的類的結構信息。我們可以通過這個對象看到類的結構。這個對象就像一面鏡子,透過這個鏡子看到類的結構,所以,我們形象的稱之為:反射。
java反射機制的概念是什么及怎么用

2. 動態語言 vs 靜態語言

(1)動態語言

是一類在運行時可以改變其結構的語言:例如新的函數、對象、甚至代碼可以 被引進,已有的函數可以被刪除或是其他結構上的變化。通俗點說就是在運行時代碼可以根據某些條件改變自身結構。

主要動態語言:Object-C、C#、JavaScript、PHP、Python、Erlang。

(2)靜態語言

與動態語言相對應的,運行時結構不可變的語言就是靜態語言。如Java、C、C++。Java不是動態語言,但Java可以稱之為“準動態語言”。即Java有一定的動態性,我們可以利用反射機制、字節碼操作獲得類似動態語言的特性。 Java的動態性讓編程的時候更加靈活!

(3)Java反射機制研究及應用

Java反射機制提供的功能

  1. 在運行時判斷任意一個對象所屬的類

  2. 在運行時構造任意一個類的對象

  3. 在運行時判斷任意一個類所具有的成員變量和方法

  4. 在運行時獲取泛型信息 在運行時調用任意一個對象的成員變量和方法

  5. 在運行時處理注解 生成動態代理

反射相關的主要API

  1. java.lang.Class:代表一個類

  2. java.lang.reflect.Method:代表類的方法

  3. java.lang.reflect.Field:代表類的成員變量

  4. java.lang.reflect.Constructor:代表類的構造器 ? … …

二、 Class類的理解

1. 類的加載過程

1.1 初步了解

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

換句話說,Class的實例就對應著一個運行時類。

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

1.2 類的加載過程圖解

當程序主動使用某個類時,如果該類還未被加載到內存中,則系統會通過如下三個步驟來對該類進行初始化。

java反射機制的概念是什么及怎么用

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

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

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

public class ClassLoadingTest {
public static void main(String[] args) {
System.out.println(A.m);
} }
class A {
static { m = 300;
}
static int m = 100;
}
//第二步:鏈接結束后m=0
//第三步:初始化后,m的值由<clinit>()方法執行決定
// 這個A的類構造器<clinit>()方法由類變量的賦值和靜態代碼塊中的語句按照順序合并產生,類似于
// <clinit>(){
// m = 300;
// m = 100;
// }
1.3 了解:什么時候會發生類初始化?

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

  1. 當虛擬機啟動,先初始化main方法所在的類

  2. new一個類的對象

  3. 調用類的靜態成員(除了final常量)和靜態方法

  4. 使用java.lang.reflect包的方法對類進行反射調用

  5. 當初始化一個類,如果其父類沒有被初始化,則先會初始化它的父類

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

  1. 當訪問一個靜態域時,只有真正聲明這個域的類才會被初始化

  2. 當通過子類引用父類的靜態變量,不會導致子類初始化

  3. 通過數組定義類引用,不會觸發此類的初始化

  4. 引用常量不會觸發此類的初始化(常量在鏈接階段就存入調用類的常量池中了)

1.4 類加載器的作用

類加載的作用:將class文件字節碼內容加載到內存中,并將這些靜態數據轉換成方法區的運行時數據結構,然后在堆中生成一個代表這個類的java.lang.Class對象,作為 方法區中類數據的訪問入口。
類緩存:標準的JavaSE類加載器可以按要求查找類,但一旦某個類被加載到類加載器 中,它將維持加載(緩存)一段時間。不過JVM垃圾回收機制可以回收這些Class對象。

java反射機制的概念是什么及怎么用

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

java反射機制的概念是什么及怎么用

1.6 代碼演示

不同類型的類的加載器:

 @Test
    public void test1(){
        //對于自定義類,使用系統類加載器進行加載
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2:系統類加載器
        //調用系統類加載器的getParent():獲取擴展類加載器
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@279f2327:擴展類加載器
        //調用擴展類加載器的getParent():無法獲取引導類加載器
        //引導類加載器主要負責加載java的核心類庫,無法加載自定義類的。
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);//null

        ClassLoader classLoader3 = String.class.getClassLoader();
        System.out.println(classLoader3);//null

    }

使用系統類加載器讀取Properties配置文件。

 /*
    Properties:用來讀取配置文件。

     */
    @Test
    public void test2() throws Exception {

        Properties pros =  new Properties();
        //此時的文件默認在當前的module下。
        //讀取配置文件的方式一://        FileInputStream fis = new FileInputStream("jdbc.properties");//        FileInputStream fis = new FileInputStream("src\\jdbc1.properties");//        pros.load(fis);

        //讀取配置文件的方式二:使用ClassLoader
        //配置文件默認識別為:當前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反射的源頭,實際上所謂反射從程序的運行結果來看也很好理解,即:可以通過對象反射求出類的名稱。

java反射機制的概念是什么及怎么用

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

Class本身也是一個類

Class 對象只能由系統建立對象

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

一個Class對象對應的是一個加載到JVM中的一個.class文件

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

通過Class可以完整地得到一個類中的所有被加載的結構

Class類是Reflection的根源,針對任何你想動態加載、運行的類,唯有先獲得相應的

3. Class類的常用方法方法

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

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

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

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

1. 調用運行時類的屬性:.class

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

2. 通過運行時類的對象,調用getClass()

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

3.調用Class的靜態方法:forName(String classPath)

前提:已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態方法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 {
            //方式一:調用運行時類的屬性:.class
            Class clazz1 = Person.class;
            System.out.println(clazz1);//class com.jiaying.java1.Person
            //方式二:通過運行時類的對象,調用getClass()
            Person p1 = new Person();
            Class clazz2 = p1.getClass();
            System.out.println(clazz2);//class com.jiaying.java1.Person

            //方式三:調用Class的靜態方法: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}

四、 創建運行時類的對象

1. 引入

有了Class對象,能做什么?

創建類的對象:調用Class對象的newInstance()方法
要求:

  1. 類必須有一個無參數的構造器。

  2. 類的構造器的訪問權限需要足夠。

難道沒有無參的構造器就不能創建對象了嗎?
不是!只要在操作的時候明確的調用類中的構造器,并將參數傳遞進去之后,才可以實例化操作。
步驟如下:

  1. 通過Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參類型的構造器

  2. 向構造器的形參中傳遞一個對象數組進去,里面包含了構造器中所需的各個參數。

  3. 通過Constructor實例化對象。

2. 語法步驟

(1)根據全類名獲取對應的Class對象

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

(2)調用指定參數結構的構造器,生成Constructor的實例

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

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

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():調用此方法,創建對應的運行時類的對象。內部調用了運行時類的空參的構造器。

        要想此方法正常的創建運行時類的對象,要求:
        1.運行時類必須提供空參的構造器
        2.空參的構造器的訪問權限得夠。通常,設置為public。


        在javabean中要求提供一個public的空參構造器。原因:
        1.便于通過反射,創建運行時類的對象
        2.便于子類繼承此運行時類時,默認調用super()時,保證父類有此構造器

         */
        Person obj = clazz.newInstance();
        System.out.println(obj);

    }

4. 體會反射的動態性

//體會反射的動態性
    @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();
            }
        }
    }

    /*
    創建一個指定類的對象。
    classPath:指定類的全類名
     */
    public Object getInstance(String classPath) throws Exception {
       Class clazz =  Class.forName(classPath);
       return clazz.newInstance();
    }}

五、獲取運行時類的完整結構

提供具有豐富內容的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. 獲取當前運行時類的屬性結構

方法作用
public Field[] getFields()返回此Class對象所表示的類或接口的publicField
public Field[] getDeclaredFields()返回此Class對象所表示的類或接口的全部Field
  • Field方法中:

方法作用
public int getModifiers()以整數形式返回此Field的修飾符
public Class<?> getType()得到Field的屬性類型
public String getName()返回Field的名稱
    @Test
    public void test1(){

        Class clazz = Person.class;

        //獲取屬性結構
        //getFields():獲取當前運行時類及其父類中聲明為public訪問權限的屬性
        Field[] fields = clazz.getFields();
        for(Field f : fields){
            System.out.println(f);
        }
        System.out.println();

        //getDeclaredFields():獲取當前運行時類中聲明的所有屬性。(不包含父類中聲明的屬性)
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
            System.out.println(f);
        }
    }

    //權限修飾符  數據類型 變量名
    @Test
    public void test2(){
        Class clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
            //1.權限修飾符
            int modifier = f.getModifiers();
            System.out.print(Modifier.toString(modifier) + "\t");

            //2.數據類型
            Class type = f.getType();
            System.out.print(type.getName() + "\t");

            //3.變量名
            String fName = f.getName();
            System.out.print(fName);

            System.out.println();
        }
    }}

2. 獲取當前運行時類的方法結構

方法作用
public Method[] getMethods()返回此Class對象所表示的類或接口的public的方法
public Method[] getDeclaredMethods()返回此Class對象所表示的類或接口的全部方法
  • Method類中:

方法作用
public Class<?> getReturnType()取得全部的返回值
public Class<?>[] getParameterTypes()取得全部的參數
public int getModifiers()取得修飾符
public Class<?>[] getExceptionTypes()取得異常信息
    @Test
    public void test1(){

        Class clazz = Person.class;

        //getMethods():獲取當前運行時類及其所有父類中聲明為public權限的方法
        Method[] methods = clazz.getMethods();
        for(Method m : methods){
            System.out.println(m);
        }
        System.out.println();
        //getDeclaredMethods():獲取當前運行時類中聲明的所有方法。(不包含父類中聲明的方法)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method m : declaredMethods){
            System.out.println(m);
        }
    }
  /*
    @Xxxx
    權限修飾符  返回值類型  方法名(參數類型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.權限修飾符
            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. 獲取當前運行時類的構造器結構

方法作用
public Constructor<T>[] getConstructors()返回此 Class 對象所表示的類的所有public構造方法。
public Constructor<T>[] getDeclaredConstructors()返回此 Class 對象表示的類聲明的所有構造方法。
  • Constructor類中:

方法作用
public int getModifiers()取得修飾符
public String getName()取得方法名稱
public Class<?>[] getParameterTypes()取得參數的類型
/*
    獲取構造器結構

     */
    @Test
    public void test1(){

        Class clazz = Person.class;
        //getConstructors():獲取當前運行時類中聲明為public的構造器
        Constructor[] constructors = clazz.getConstructors();
        for(Constructor c : constructors){
            System.out.println(c);
        }

        System.out.println();
        //getDeclaredConstructors():獲取當前運行時類中聲明的所有的構造器
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for(Constructor c : declaredConstructors){
            System.out.println(c);
        }

    }
 /*
    獲取運行時類的父類

     */
    @Test
    public void test2(){
        Class clazz = Person.class;

        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
    }

    /*
    獲取運行時類的帶泛型的父類

     */
    @Test
    public void test3(){
        Class clazz = Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }

    /*
    獲取運行時類的帶泛型的父類的泛型


    代碼:邏輯性代碼  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());
    }/*
    獲取運行時類實現的接口
     */
    @Test
    public void test5(){
        Class clazz = Person.class;

        Class[] interfaces = clazz.getInterfaces();
        for(Class c : interfaces){
            System.out.println(c);
        }

        System.out.println();
        //獲取運行時類的父類實現的接口
        Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
        for(Class c : interfaces1){
            System.out.println(c);
        }

    }
    /*
        獲取運行時類所在的包

     */
    @Test
    public void test6(){
        Class clazz = Person.class;

        Package pack = clazz.getPackage();
        System.out.println(pack);
    }

    /*
        獲取運行時類聲明的注解

     */
    @Test
    public void test7(){
        Class clazz = Person.class;

        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annos : annotations){
            System.out.println(annos);
        }
    }}

六、調用運行時類的指定結構

關于setAccessible方法的使用

MethodFieldConstructor對象都有setAccessible()方法。

setAccessible啟動和禁用訪問安全檢查的開關。

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

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

1. 調用運行時類中指定的屬性

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

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

在Field中:

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

代碼演示:

public class ReflectionTest {
    @Test
    public void testField() throws Exception {
        Class clazz = Person.class;

        //創建運行時類的對象
        Person p = (Person) clazz.newInstance();


        //獲取指定的屬性:要求運行時類中屬性聲明為public
        //通常不采用此方法
        Field id = clazz.getField("id");

        /*
        設置當前屬性的值

        set():參數1:指明設置哪個對象的屬性   參數2:將此屬性值設置為多少
         */

        id.set(p,1001);

        /*
        獲取當前屬性的值
        get():參數1:獲取哪個對象的當前屬性值
         */
        int pId = (int) id.get(p);
        System.out.println(pId);


    }
    /*
    如何操作運行時類中的指定的屬性 -- 需要掌握
     */
    @Test
    public void testField1() throws Exception {
        Class clazz = Person.class;

        //創建運行時類的對象
        Person p = (Person) clazz.newInstance();

        //1. getDeclaredField(String fieldName):獲取運行時類中指定變量名的屬性
        Field name = clazz.getDeclaredField("name");

        //2.保證當前屬性是可訪問的
        name.setAccessible(true);
        //3.獲取、設置指定對象的此屬性值
        name.set(p,"Tom");

        System.out.println(name.get(p));
    }

2. 調用運行時類中的指定的方法

通過反射,調用類中的方法,通過Method類完成。步驟:

  1. 通過Class類的getMethod(String name,Class…parameterTypes)方法取得 一個Method對象,并設置此方法操作時所需要的參數類型。

  2. 之后使用Object invoke(Object obj, Object[] args)進行調用,并向方法中 傳遞要設置的obj對象的參數信息。

java反射機制的概念是什么及怎么用

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

若原方法若為靜態方法,此時形參Object obj可為null

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

代碼演示:

 /*
    如何操作運行時類中的指定的方法 -- 需要掌握
     */
    @Test
    public void testMethod() throws Exception {

        Class clazz = Person.class;

        //創建運行時類的對象
        Person p = (Person) clazz.newInstance();

        /*
        1.獲取指定的某個方法
        getDeclaredMethod():參數1 :指明獲取的方法的名稱  參數2:指明獲取的方法的形參列表
         */
        Method show = clazz.getDeclaredMethod("show", String.class);
        //2.保證當前方法是可訪問的
        show.setAccessible(true);

        /*
        3. 調用方法的invoke():參數1:方法的調用者  參數2:給方法形參賦值的實參
        invoke()的返回值即為對應類中調用的方法的返回值。
         */
        Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");
        System.out.println(returnValue);

        System.out.println("*************如何調用靜態方法*****************");

        // private static void showDesc()

        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果調用的運行時類中的方法沒有返回值,則此invoke()返回null//        Object returnVal = showDesc.invoke(null);
        Object returnVal = showDesc.invoke(Person.class);
        System.out.println(returnVal);//null

    }

3. 調用運行時類中的指定的構造器

代碼演示:

  /*
    如何調用運行時類中的指定的構造器
     */
    @Test
    public void testConstructor() throws Exception {
        Class clazz = Person.class;

        //private Person(String name)
        /*
        1.獲取指定的構造器
        getDeclaredConstructor():參數:指明構造器的參數列表
         */

        Constructor constructor = clazz.getDeclaredConstructor(String.class);

        //2.保證此構造器是可訪問的
        constructor.setAccessible(true);

        //3.調用此構造器創建運行時類的對象
        Person per = (Person) constructor.newInstance("Tom");
        System.out.println(per);

    }}


以上就是“java反射機制的概念是什么及怎么用”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

北流市| 阳信县| 邹平县| 永清县| 金门县| 昌江| 神农架林区| 改则县| 犍为县| 济南市| 阿鲁科尔沁旗| 京山县| SHOW| 瑞安市| 湘潭市| 嘉义县| 泰和县| 遂平县| 汉阴县| 杭锦后旗| 禹城市| 红安县| 德保县| 博爱县| 新郑市| 呼伦贝尔市| 延寿县| 汨罗市| 从化市| 普陀区| 滦南县| 谢通门县| 凤山县| 通榆县| 克什克腾旗| 定襄县| 永胜县| 汉川市| 壤塘县| 乌兰浩特市| 砚山县|