java_反射

java_反射

什麼是反射

概念

  • 放射:將類的各個部分封裝爲其餘對象,這就是反射機制。

java代碼在內存中經歷的三個階段

一、 Source 源代碼階段java

  • 執行javac編譯命令從.java文件到.class文件的過程都是在源代碼階段,.class字節碼文件會將類分爲多個部分,其中分爲成員變量部分,成員方法部分,構造方法部分等。

二、 Class 類對象階段dom

  • 經過ClassLoader(類加載器)將字節碼文件加載到內存中。
  • 經過Class類對象來描述進入內存中的字節碼文件的特徵和行爲。將成員變量、成員方法、構造方法等封裝成單獨的對象放入Class類對象中。
  • 最後咱們能夠經過Class對象的一些行爲建立具體的某個對象。

三、 runtime 運行時階段ide

  • new 類();

反射的好處

  • 在程序的運行期間操做這些對象。
  • 下降程序的耦合性,提升程序的可擴展性。

獲取Class類對象的方法

  • 獲取class類對象的方式有三種,分別對應的java代碼經歷的三個階段

一、 Class.forName("全類名");3d

  • 將字節碼文件加載進內存,返回class對象
  • 多用於配置文件,將類名定義在配置文件中

二、 類名.class;code

  • 經過類名的屬性class獲取
  • 多用於參數傳遞

三、 對象.getClass();對象

  • getClass()方法是定義在Object類中的
  • 多用於對象獲取字節碼blog

  • 同一個字節碼文件(*.class)在一次程序運行過程當中,只會被加載一次。內存

package top.uaoie.day03;
import top.uaoie.domain.Person;
public class ReflectDome01 {
    public static void main(String[] args) throws Exception {
        //1. Class.forName("全類名");
        Class clazz1 = Class.forName("top.uaoie.domain.Person");
        //2. 類名.class;
        Class clazz2 = Person.class;
        //3. 對象.getClass();
        Person p = new Person();
        Class clazz3 = p.getClass();

        System.out.println(clazz1);
        System.out.println(clazz2);
        System.out.println(clazz3);
        //比較三個對象
        System.out.println(clazz1 == clazz2);
        System.out.println(clazz1 == clazz3);
    }
}


反射的應用

一、 獲取全部的成員變量字符串

  • Field[] getFields()
  • Field getFied(String name)
  • Field[] getDeclaredFields()
  • Field getDeclaredFied(String name)

二、 獲取全部的構造方法get

  • Constructor<?>[] getConstructors()
  • Constructor getConstructors(類<?>... parameterTypes)
  • Constructor<?>[] getDeclaredConstructors()
  • Constructor getDeclaredConstructors(類<?>... parameterTypes)

三、 獲取全部的成員方法

  • Method[] getMethods()
  • Menthod getMethod(String name,類<?>...parameterTypes)
  • Method[] getDeclaredMethods()
  • Menthod getDeclaredMethod(String name,類<?>...parameterTypes)

四、 獲取類名

  • String getName()

如下爲演示經過反射獲取全部的成員變量

  • 建立一個名爲Person的類,裏面的代碼以下:
package top.uaoie.domain;
public class Person {
    public String a;
    protected String b;
    String c;
    private String d;

    @Override
    public String toString() {
        return "Person{" +
                "a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                '}';
    }
}
  • 再新建一個名爲ReflectDome02的類,裏面的代碼以下:
package top.uaoie.day03;
import top.uaoie.domain.Person;
import java.lang.reflect.Field;
public class ReflectDome02 {
    public static void main(String[] args) throws Exception {
        //獲取Person的Class對象,此處是在階段二部分獲取的
        //也可在第一階段獲取,如:Class.forName("top.uaoie.domain.Person");
        Class p = Person.class;
        //獲取成員變量
        Field[] fields = p.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("---------------------");
        Field a = p.getField("a");
        System.out.println(a);
        //建立一個對象
        Person person = new Person();
        //獲取成員變量a的值
        Object value = a.get(person);
        System.out.println(value);
        //設置成員變量a的值
        a.set(person, "這是a的值");
        System.out.println(person);
        System.out.println("=================");
        Field[] declaredFields = p.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        Field d = p.getDeclaredField("d");
        //忽略訪問權限修飾符
        d.setAccessible(true);//暴力反射
        Object value2 = d.get(person);
        System.out.println(value2);

    }
}

小結

  • 獲取類的class對象有多種方法,其中使用Class.forName能夠經過讀取配置文件獲取全類名
  • Class.forName和getField等類是代碼會報錯是由於傳入的是字符串,全部可能不存在這個類獲或者方法,因此須要處理異常
  • 經過反射能夠直接訪問到任何成員變量名,不受訪問修飾符的限制
  • 能夠setAccessible設置爲true來暴力反射獲取或者更改爲員變量的值
相關文章
相關標籤/搜索