天天看點

Java中的反射是什麼?

類加載器

  • 什麼是類加載器 
  • 類加載器的職責 
  • 類加載器的組成

反射 

  • 什麼是反射 
  • 如何使用反射

什麼是類加載器 

當Java程式要使用某個類時,如果該類還沒有被加載到記憶體中,則系統會通過加載,連結,初始化這三步來實作對這個類進行初始化。 

加載 

就是指将class檔案讀入記憶體,并為之建立一個Class對象。 

任何類被使用時系統都會建立一個Class對象。 

連結 

驗證 是否有正确的内部結構,并和其他類協調一緻。 

準備 負責為類的靜态成員配置設定記憶體,并設定預設初始化值。 

解析 将類的二進制資料中的符号引用替換為直接引用。 

初始化 

類的初始化,不做過多叙述

類的初始化時機 (什麼時候會被加載到記憶體)

  • 建立類的執行個體
  • 通路類的靜态變量,擷取為靜态變量指派
  • 使用類的靜态方法
  • 使用反射來強制建立某個類或者接口對應得Class對象
  • 初始化某個類的子類(父類先加載到記憶體中) 
  • 使用java.exe指令來運作某個主類

當以上條件滿足任意一條時,類就會被初始化

類加載器的職責

負責将.class 檔案加載待記憶體中,并産生Class對象。 

類加載器的組成

  • Bootstrap ClassLoader 根類加載器(C代碼完成) ,負責加載Java運作的核心類 ,在jreb 目錄下有個 rt.jar,這個就是系統編譯好的核心類庫,Bootstrap 就負責加載rt.jar
  • Extension ClassLoader 擴充類加載器(C代碼完成) ,負責加載程式中額擴充應用,擴充應用類在jreb/ext目錄下。
  • System ClassLoader 系統類加載器(Java代碼完成) ,System ClassLoader負責加載我們寫的類 

什麼是反射

  • Java反射機制是在運作狀态中,對于任意一個類,都能知道這個類的是以屬性和方法;對于任何一個對象,都能夠調用它的任何一個方法和屬性;這樣動态擷取新的以及動态調用對象方法的功能就叫做反射。
  • 簡單來說反射就是解剖一個類,然後擷取這個類中的屬性和方法,前提是要擷取這個類的Class對象
  • 在java中給我們提供了幾個這幾個類用于描述編譯後的各種對象
Java中的反射是什麼?

如何使用反射 

A . 使用Class類,擷取出被解剖的這個類的class檔案對象 

B . 使用Class類方法,擷取出類中的所有成員 

C . 将成員擷取出來後,交給對應類,對應類中的方法,運作成員

如何擷取,class檔案對象

  1. 使用類的對象擷取每個類都使用Object作為父類,Object類方法 getClass() 傳回這個類的class檔案對象,方法傳回值Class類型對象
  2. 使用類的靜态屬性擷取類名.class 傳回這個類的class檔案對象.屬性運作結果也是Class類型對象
  3. 使用Class類的靜态方法擷取Class類靜态方法 forName(String 類名) 傳遞字元串類名擷取到這個類的class檔案對象,方法傳回值也是Class類型對象

不管用哪種方式擷取的Class對象,他們都是相等的。

package com.test.demo;
/**
 * 定義person類
 */
public class Person {

}

package com.test.demo;

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException {

        //第1種方式擷取Class對象

        Person p1=new Person();
        Class cc=p1.getClass();
        System.out.println(cc);

        //第2種方式擷取Class對象
        Class cc2=Person.class;
        System.out.println(cc2);
        //第3種方式擷取Class對象
        Class cc3=Class.forName("com.test.demo.Person");//全類名
        System.out.println(cc3);

        System.out.println(cc==cc2);
        System.out.println(cc2==cc3);
    }
}


//輸出結果
class com.test.demo.Person
class com.test.demo.Person
class com.test.demo.Person
true
true
           

擷取構造

為Person類增加構造

public Person(){
        System.out.println("Person類無參數構造");
    }
    public Person(int a,int b,String s){
        System.out.println("Person類有參數構造:a:"+a+" b:"+b+" s:"+s);
    }

    private Person(int a){
        System.out.println("Person類有參數   私有 構造:a:"+a);
    }



package com.test.demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        Class clazz=Person.class;
        //擷取Person類所有 公共 構造
        Constructor [] conarr=clazz.getConstructors();

        for(Constructor con :conarr){
            System.out.println(con);
        }
        //擷取指定構造方法
        //無參數
        Constructor cc=clazz.getConstructor();
        Object oo=cc.newInstance();

        //有參數
        Constructor cc2=clazz.getConstructor(int.class,int.class,String.class);
        Object oo2=cc2.newInstance(1,2,"haha");

        //擷取私有構造方法
        Constructor cc3=clazz.getDeclaredConstructor(int.class);
        //暴力通路
        cc3.setAccessible(true);
        Object oo3=cc3.newInstance(1);

        clazz.newInstance();//直接擷取空參數構造,必須是public
    }
}

輸出結果
public com.test.demo.Person()
public com.test.demo.Person(int,int,java.lang.String)
Person類無參數構造
Person類有參數構造:a:1 b:2 s:haha
Person類有參數   私有 構造:a:1
Person類無參數構造
           

擷取成員變量

為Person類增加成員變量

    public String name="smt";
    private String idcard="1001u09t";

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "name:"+name+"  idcard:"+idcard;
    }

package com.test.demo;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException,
            NoSuchMethodException, SecurityException, InstantiationException,
            IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, NoSuchFieldException {

        Class clazz = Person.class;
        Object obj = clazz.newInstance();
        // 擷取Person類所有 公共 成員變量
        Field[] fields = clazz.getFields();
        for(Field s:fields){
            System.out.println(s);
        }

        Field field=clazz.getField("name");

        field.set(obj, "haha");

        System.out.println(obj);

        Field field2=clazz.getDeclaredField("idcard");
        field2.setAccessible(true);
        field2.set(obj, "123456");
        System.out.println(obj);
    }
}

輸出結果
Person類無參數構造
public java.lang.String com.test.demo.Person.name
name:haha  idcard:1001u09t
name:haha  idcard:123456
           

擷取成員方法

為Person類增加成員方法

    public void show(){
        System.out.println("show 空參數");
    }
    public void show(int a){
        System.out.println("show   a:"+a);
    }   
    private void show(String s){
        System.out.println("show   s:"+s);
    }

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException,
            NoSuchMethodException, SecurityException, InstantiationException,
            IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, NoSuchFieldException {


        Class clazz = Person.class;
        Object obj = clazz.newInstance();
        // 擷取Person類所有 公共 成員方法
        Method [] methods=clazz.getMethods();

        for(Method m:methods){
            System.out.println(m);
        }

        Method m=clazz.getMethod("show");
        m.invoke(obj);

        Method m1=clazz.getMethod("show",int.class);
        m1.invoke(obj,1);

        Method m2=clazz.getDeclaredMethod("show",String.class);
        m2.setAccessible(true);
        m2.invoke(obj,"smt");
    }
}


輸出結果:
Person類無參數構造
public java.lang.String com.test.demo.Person.toString()
public void com.test.demo.Person.show(int)
public void com.test.demo.Person.show()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
show 空參數
show   a:1
show   s:smt
           

我有一個微信公衆号,經常會分享一些Java技術相關的幹貨;如果你喜歡我的分享,可以用微信搜尋“Java團長”或者“javatuanzhang”關注。

參考:

  • Java基礎之—反射(非常重要)
  • Java 反射 使用總結
  • 深入了解Java反射

繼續閱讀