反射

反射
在運行狀態中,對於任意一個類都能知道這個類的所有屬性和方法,對於任意一個對象,都能夠調用任意一個方法和屬性。簡單來說就是:根據現有對象倒推類的組成
反射的作用:
反編譯過程:使得在運行時就可獲得class文件的信息
**

取得Class對象的三種方法:**

1.使用Object類的getClass():但要用這個類的實例來調用
2.類名.calss
3.使用Class類提供的forName(String className):傳入的名稱必須是類的全限定名
區別:

//這是我定義的一個類  裏面有靜態代碼塊
class Person{
    private String name;
    private int age;
    public Person(){}
    public  void test(){
        System.out.println("good");
    }
    //注意
    static {
        System.out.println("static port");
    }
}
//使用getClass()
Person person = new Person();
        Class<?> c = person.getClass();
//使用類名.class
Class<?> cl = Person.class;
//使用Class類的forName()
Class<?> cls = Class.forName("www.bite.reflect.Person");

通過運行程序可先看到一個現象
在這裏插入圖片描述
只有使用類名.class這種方法獲取類的class對象時沒有加載靜態代碼塊,這說明此時並沒有加載類,但是使用Object類的getClass()方法需要用該類的實例來調用,這時已經有該類的實例了,而使用forname()這種方法既不需要實例對象,又加載了類。

通過反射取得實例化對象:

public T newInstance()
        throws InstantiationException, IllegalAccessException

通過class對象調用newInstance()方法取得該類的實例化對象
通過這種方法取得類的實例是應該在類中保留一個無參構造(還有一種用構造方法調用newInstance()取得類實例的方法在下面詳細說明)
應用:反射實現工廠模式,達到具體子類增加也不需要修改工廠類的代碼
核心代碼 以後再對工廠模式進行總結
在這裏插入圖片描述

反射與類操作

通過反射取得父類信息:

1.取得包信息:

public Package getPackage()

2.取得父類的Class對象:

public native Class<? super T> getSuperclass();

3.取得所有實現的父接口:

public Class<?>[] getInterfaces()

反射調用構造:

1.取得指定參數的構造:

//getConstructor()方法只能取得public權限的
Constructor<?> con = cls.getConstructor(int.class,String.class);

getDeclaredConstructor(參數)——與權限無關
2.取得所有構造:

//僅限於public權限
Constructor<?>[] cons = cls.getConstructors();

getDeclaredConstructors()——與權限無關
使用Constructor類的newInstance():

//取得指定構造方法
Constructor<?> con = cls.getConstructor(int.class,String.class);
//通過給newInstance()方法傳指定格式單位參數實例化類對象
System.out.println(con.newInstance(21,"liyifeng"));

如果取得的構造函數是private權限的話,可以通過構造函數的對象設置setAccessible(true)動態破壞封裝,盡在本次JVM金正中有效。

反射調用普通方法:

1.取得全部普通方法:
getMethods();
2.取得指定普通方法:
getMethod(方法名,方法參數類型)
調用方法的支持:invoke(實例對象,調用的參數)——我理解爲利用反射拿到方法的對象後利用invoke去調用這個方法
例如:

Liyifeng liyifeng = (Liyifeng) cls.newInstance();
        //得到指定方法的對象
        Method setNameMethod = cls.getMethod("setName", String.class);
        //invoke是一個調用方法的支持  
        //invoke方法的參數:代調用方法的實例對象 方法需要傳入的參數   
        //實際這裏相當於liyifeng.setName("offila")
        setNameMethod.invoke(liyifeng,"offila");//此時已經調用setName方法修改了名字
        Method getNameMethod = cls.getMethod("getName");
        System.out.println(getNameMethod.invoke(liyifeng));

反射調用類中屬性:

類中的所有屬性都在類對象實例化之後纔會分配空間,所以此時要想調用類的屬性,就要先拿到類的實例化對象。
1.取得類中所有屬性:
getFields()——父類
getDeclaredFields()——子類
2.取得類中指定屬性
getField(屬性名)——父類
getDeclaredField(屬性名)——子類
在取得父類屬性時有權限限制,只能取得父類public權限的屬性,本類屬性沒有限制
File類中的方法:
set(實例對象,要設置的值)
get(實例對象)
getType()
方法的使用

 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        Class<?> cls = Class.forName("www.bite.reflect.B");
        Object object = cls.newInstance();
        Field field = cls.getDeclaredField("school");
        field.setAccessible(true);
        field.set(object,"XUST");
        System.out.println(field.get(object));
        System.out.println(field.getType().getName());//得到類的全限定名
        System.out.println(field.getType().getSimpleName());//得到類名
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章