Java進階之reflection(反射機制)——反射概念與基礎

轉自: https://blog.csdn.net/xu__cg/article/details/52877573  

  反射機制是Java動態性之一,而說到動態性首先得了解動態語言。那麼何爲動態語言?

一、動態語言


動態語言,是指程序在運行時可以改變其結構:新的函數可以引進,已有的函數可以被刪除等結構上的變化。比如常見的JavaScript就是動態語言,除此之外Ruby,Python等也屬於動態語言,而C、C++則不屬於動態語言。

二、Java是動態語言嗎?


從動態語言能在運行時改變程序結構結構或則變量類型上看,Java和C、C++一樣都不屬於動態語言。 
但是JAVA卻又一個非常突出的與動態相關的機制:反射機制。Java通過反射機制,可以在程序運行時加載,探知和使用編譯期間完全未知的類,並且可以生成相關類對象實例,從而可以調用其方法或則改變某個屬性值。所以JAVA也可以算得上是一個半動態的語言

三、反射機制:


1.反射機制概念 
在Java中的反射機制是指在運行狀態中,對於任意一個類都能夠知道這個類所有的屬性和方法;並且對於任意一個對象,都能夠調用它的任意一個方法;這種動態獲取信息以及動態調用對象方法的功能成爲Java語言的反射機制。

2.反射的應用場合 
在Java程序中許多對象在運行是都會出現兩種類型:編譯時類型和運行時類型。 
編譯時的類型由聲明對象時實用的類型來決定,運行時的類型由實際賦值給對象的類型決定 

如:

Person p=new Student();

其中編譯時類型爲Person,運行時類型爲Student。 
除此之外,程序在運行時還可能接收到外部傳入的對象,該對象的編譯時類型爲Object,但是程序有需要調用該對象的運行時類型的方法。爲了解決這些問題,程序需要在運行時發現對象和類的真實信息。然而,如果編譯時根本無法預知該對象和類屬於哪些類,程序只能依靠運行時信息來發現該對象和類的真實信息,此時就必須使用到反射了。

四、Java反射API


反射API用來生成JVM中的類、接口或則對象的信息。 
Class類:反射的核心類,可以獲取類的屬性,方法等信息。 
Field類:Java.lang.reflec包中的類,表示類的成員變量,可以用來獲取和設置類之中的屬性值。 
Method類: Java.lang.reflec包中的類,表示類的方法,它可以用來獲取類中的方法信息或者執行方法。 
Constructor類: Java.lang.reflec包中的類,表示類的構造方法。

五、使用反射的步驟


1.步驟

  • 獲取想要操作的類的Class對象
  • 調用Class類中的方法
  • 使用反射API來操作這些信息

2.獲取Class對象的方法

  • 調用某個對象的getClass()方法
    Person p=new Person();
    Class clazz=p.getClass();
  • 調用某個類的class屬性來獲取該類對應的Class對象
    Class clazz=Person.class;
  • 使用Class類中的forName()靜態方法; (最安全/性能最好)
    Class clazz=Class.forName("類的全路徑"); (最常用)

3.獲取方法和屬性信息

當我們獲得了想要操作的類的Class對象後,可以通過Class類中的方法獲取並查看該類中的方法和屬性。 
示例代碼

<<<<<<<<<<<<<<<<<<<<<<Person類<<<<<<<<<<<<<<<<<<<<<<<<<<
package reflection;

public class Person {
    private String name;
    private String gender;
    private int age;

    public Person() {

    }
    public Person(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    //getter和setter方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public String toString(){
        return "姓名:"+name+"  性別:"+gender+"  年齡:"+age;
    }

}
<<<<<<<<<<<<<<<<使用反射<<<<<<<<<<<<<<<<<<<
package reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/*
 * 通過用戶輸入類的全路徑,來獲取該類的成員方法和屬性
 * Declared獲取全部不管是私有和公有
 * 1.獲取訪問類的Class對象
 * 2.調用Class對象的方法返回訪問類的方法和屬性信息
 */
public class Test {

    public static void main(String[] args) {
        try {
            //獲取Person類的Class對象
            Class clazz=Class.forName("reflection.Person");

            //獲取Person類的所有方法信息
            Method[] method=clazz.getDeclaredMethods();
            for(Method m:method){
                System.out.println(m.toString());
            }

            //獲取Person類的所有成員屬性信息
            Field[] field=clazz.getDeclaredFields();
            for(Field f:field){
                System.out.println(f.toString());
            }

            //獲取Person類的所有構造方法信息
            Constructor[] constructor=clazz.getDeclaredConstructors();
            for(Constructor c:constructor){
                System.out.println(c.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

輸出結果:

方法信息: 
public java.lang.String reflection.Person.toString() 
private java.lang.String reflection.Person.getName() 
private void reflection.Person.setName(java.lang.String) 
public void reflection.Person.setAge(int) 
public int reflection.Person.getAge() 
public java.lang.String reflection.Person.getGender() 
public void reflection.Person.setGender(java.lang.String) 
屬性信息: 
private java.lang.String reflection.Person.name 
private java.lang.String reflection.Person.gender 
private int reflection.Person.age 
構造方法信息 
private reflection.Person() 
public reflection.Person(java.lang.String,java.lang.String,int)

4.創建對象

當我們獲取到所需類的Class對象後,可以用它來創建對象,創建對象的方法有兩種:

  • 使用Class對象的newInstance()方法來創建該Class對象對應類的實例,但是這種方法要求該Class對象對應的類有默認的空構造器。
  • 先使用Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來創建 Class對象對應類的實例,通過這種方法可以選定構造方法創建實例。

示例代碼:

package reflection;

import java.lang.reflect.Constructor;
public class Demo01 {

    public static void main(String[] args) {
        try {
            //獲取Person類的Class對象
            Class clazz=Class.forName("reflection.Person"); 
            /**
             * 第一種方法創建對象
             */
            //創建對象
            Person p=(Person) clazz.newInstance();
            //設置屬性
            p.setName("張三");
            p.setAge(16);
            p.setGender("男");
            System.out.println(p.toString());

            /**
             * 第二種方法創建
             */
            //獲取構造方法
            Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
            //創建對象並設置屬性
            Person p1=(Person) c.newInstance("李四","男",20);
            System.out.println(p1.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

輸出結果:

姓名:張三 性別:男 年齡: 16 
姓名:李四 性別:男 年齡: 20

好了,以上是Java反射機制的簡單介紹,下一篇文章我將講一下反射的兩個具體應用,通過反射操作註解通過反射操作泛型,有興趣的同學可以瞭解一波。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章