二十六、Java--------反射

 

反射

    正常情況下,我們必須知道一個類的完整路徑後纔可以實例化對象,但是在Java也可以通過一個對象來找到其所在類的信息,這其實就是Class的功能。

可以看到此時的所有操作都是反着來,這就是反射。

package reflect;

class X{

    

}

public class GetClassDemo01 {

    public static void main(String[] args) {

        X x=new X();

        System.out.println(x.getClass().getName());

    }

}

  

Class

    Class本身表示一個類的本身,通過Class可以完整的得到一個類的完整結構,包括此類中的方法定義、屬性定義等。

  

        此類在jdk中文檔中沒有發現任何構造方法,所以此類的構造方法是被私有化了。

實例化Class 類對象的三種方式

    第一種:通過forName()方法

        ♥ 第二種: 通過類class

        ♥ 第三種:通過對象.getClass()

package reflect;

class X{

    

}

public class GetClassDemo01 {

    public static void main(String[] args) {

        Class <?> c1=null;

        Class <?> c2=null;

        Class <?> c3=null;

        try {

            //通過第一種方式實例化Class對象,這種方法也是最常用的一種形式

            c1=Class.forName("reflect.X");

            //通過Object類中的放過實例化Class對象

            c2=new X().getClass();

            //通過類.cass實例化Class

            c3=X.class;

            System.out.println("類名稱:" + c1.getName() );

            System.out.println("類名稱:" + c2.getName() );

            System.out.println("類名稱:" + c3.getName() );

        } catch (ClassNotFoundException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }

}

     一旦可以實例化Class對象之後就可以進行反射的進一步操作了。

Class的使用

    Class主要是反射的源頭,不光可以取得對象所在類的信息,也可以直接通過Class類的方法進行對象的實例化對象操作,使用關鍵字new爲對象實例化,如果現在已經實例化好Class對象,則可以通過Class類提供的newInstance()方法實例化對象。

package reflect;

class Person{

    private String name;

    private int age;

    @Override

    public String toString(){//爲了操作方便,複寫toString放過

        return "姓名:"+this.name+",年齡"+this.age;

        

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

    

}

public class InstanceDemo01 {

    public static void main(String[] args) {

        Class<?> c=null;

        try {

            c=Class.forName("reflect.Person");

            Person per=null;

            per=(Person) c.newInstance();//實例化對象

            per.setName("月芽之上");

            per.setAge(24);

            System.out.println(per.toString());

            

            

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        } catch (InstantiationException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (IllegalAccessException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        

    }

}

   通過以上的代碼可以發現,即使不適用 new關鍵字對象也可以進行實例化操作,這也就是反射的作用。但是我們也發現在使用以上操作的時候有一點需要注意,就是所操作的類中必須有午餐構造函數,否則無法進行實例化!

爲了解決這一問題,我們需要明確的指明要調用的方法,並傳遞參數,(實際開發中一般會有午無參構造)。步驟如下:

  ❤ 1、通過Class類中的getConstructors()取得本類中的全部構造方法。

    ❤ 2、向構造方法中傳遞一個對象數組進去,裏面包含了構造方法中所需的各個參數

    ❤ 3、之後通過Constructor實例化對象

        Construction類中存在一個方法:

        public T newInstance(Object... initargs)

                        throws InstantiationException,

                        IllegalAccessException,

                        IllegalArgumentException,

                        InvocationTargetException

        傳遞參數初始化,以進行對象的實例化操作。

Constru中常用方法:

調用帶參數的構造方法示例

package reflect;

  

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

  

class Person{

    private String name;

    private int age;

    public Person(String name,int age){//定義一個有兩個參數的構造函數,此時當前類不再存在無參構造

        this.name=name;

        this.age=age;

    }

    @Override

    public String toString(){//爲了操作方便,複寫toString放過

        return "姓名:"+this.name+",年齡"+this.age;

        

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

    

}

public class InstanceDemo01 {

    public static void main(String[] args) {

        Class<?> c=null;

        try {

            c=Class.forName("reflect.Person");

            Constructor<?> cons[]=null;

            cons=c.getConstructors();

            

            Person per=null;

            

            per=(Person) cons[0].newInstance("月芽之上",24);//實例化對象

            

            System.out.println(per.toString());

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        } catch (InstantiationException e) {

            e.printStackTrace();

        } catch (IllegalAccessException e) {

            e.printStackTrace();

        } catch (IllegalArgumentException e) {

            e.printStackTrace();

        } catch (InvocationTargetException e) {

            e.printStackTrace();

        }

        

    }

}

通過反射獲取類的結構

    在實際開發中,上面介紹的程序就是反射用的最多的情況,當然反射機制所提供的功能遠不止這些,還可以通過反射獲取一個類的完整結構,那麼這是就要使用到java.lang.reflect保重的一些幾個類。

    ❤ 1Constructor :表示類中的構造方法

        ❤ 2Filed :表示類中的屬性

        ❤ 3Method :表示類中的方法

這三個類都是AccessibleObject的子類

  

package reflect.construction;

interface China{

    String NATIONAL="China";//定義全局變量

    String AUTHOR="月芽之上";//定義全局變量

    void sayChina();

    String sayHello(String name,int age);

}

public class Person implements China {

    private String name;

    private int age;

    Person(){//參構造

    }

    Person(String name){//設置name

    this.name=name;

    }

    Person(String name,int age){//設置name

        this.name=name;

        this.age=age;

        }

    @Override

    public void sayChina() {

        System.out.println("作者:"+AUTHOR+",國籍"+NATIONAL);

    }

    @Override

    public String sayHello(String name, int age) {

        return name+",你好,我今年"+ age+"歲了!";

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

}

取得類所實現的全部接口

    要取得一個類所實現的接口,則必須使用Class類中的getInterfaces()方法。此方法定義如下:

public Class<?>[] getInterfaces()

方法的返回值是一個class類的對象數組,之後就可以直接利用Class類中的getName()方法輸出即可、

public class GetInterfaceDemo {

    public static void main(String[] args) {

        Class<?> c1=null;

        try {

            c1=Class.forName("reflect.construction.Person");

            Class<?> c[]=c1.getInterfaces();

            for(int i=0;i<c.length;i++){

                System.out.println(c[i].getName());

            }

        

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

        

    }

}

取得該類所繼承的父類

    一個類可與有多個實現,但是卻只能有一個直接父類,所以想要取得一個類的父類,可以使用Class類中的getSuperclass()方法。

public Class<? super T> getSuperclass()

此方法返回的是Class實例,和之前取得接口一樣,可以通過getName(0方法取得名次

public class GetSuperClassDemo {

    public static void main(String[] args) {

        Class<?> c1 = null;

        try {

            c1 = Class.forName("reflect.construction.Person");

            Class<?> c = c1.getSuperclass();

            System.out.println(c.getName());

  

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

    }

}

取得全部構造函數

import java.lang.reflect.Constructor;

public class GetConstructorDemo {

    public static void main(String[] args) {

        Class<?> c1=null;

        try {

            c1=Class.forName("reflect.construction.Person");//實例化Class對象

            Constructor<?>[] cons=c1.getConstructors();//得到全部構造方法

            for(int i=0;i<cons.length;i++){

                System.out.println(cons[i]);//打印所以構造方法

            }

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

        

    }

}

取得類中的方法

    要取出一個類中的全部方法,可以使用Class類中的getDeclaredMethods()方法,此方法返回的是一個Method類的對象數組。而想取得方法的具體信息例如:方法參數、拋出的異常等等,就必須依靠Mehod類。

public Method getDeclaredMethod(String name, Class<?>... parameterTypes)                    取出本類的全部方法

                throws NoSuchMethodException,SecurityException

 

public Method[] getMethods()                                                                  取得全部方法

                 throws SecurityException

  

public class GetMethodDemo {

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

        Class<?> c1=null;

        c1=Class.forName("reflect.construction.Person");

        Method m[]=c1.getMethods();

        for(int i=0;i<m.length;i++){

            System.out.println(m[i]);

        }

    }

}

取出類中的屬性:

依賴的方法:

public Field[] getFields()  throws SecurityException

 

public Field[] getDeclaredFields()  throws SecurityException

 

 

public class GetFiledDemo {

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

        Class<?> c1=null;

        c1=Class.forName("reflect.construction.Person");

        Field f[]=c1.getFields();

        for(int i=0;i<f.length;i++)

        {

            System.out.println(f[i]);

        }

    }

}

通過反射調用類中的方法

    在正常情況下一個類對象產生後就可以直接調用類中的方法了.如果要調用的話肯定必須清楚的指定調用的方法名是什麼,之後通過Class 中的getMethod()方法。

public Method getMethod(String name, Class<?>... parameterTypes)

                   throws NoSuchMethodException, SecurityException

該方法得到的Method對象,之後通過此Method對象來執行方法,但是在調用的時候因爲會涉及到參數的問題,所以通過getMehod()取得的時候需要要設置好對應的參數類型。

比如調用Person中sayChina()方法,因爲該方法中沒有任何參數,所以只需要調用Method 中invoke()方法。

public Object invoke(Object obj,Object... args)
                throws IllegalAccessException,IllegalArgumentException,InvocationTargetException

執行的時候需要還需要傳遞參數進去, 而且需要實例化對象。

public class InvokeSayChinaDemo {

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

        Class<?> c1=null;

        c1=Class.forName("reflect.construction.Person");//實例化Class對象

        Method met=c1.getMethod("sayChina");//找到sayChina()方法

        met.invoke(c1.newInstance());//調用方法

    }

}

調用有參數的方法

public class InvokeSayChinaDemo {

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

        Class<?> c1=null;

        c1=Class.forName("reflect.construction.Person");//實例化Class對象

        Method met=c1.getMethod("sayHello",String.class,int.class);//找到sayHello()方法

        String returnValue=(String) met.invoke(c1.newInstance(),"李佔祥",24);//調用方法

        System.out.println(returnValue);

    }

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