JAVA反射知識基本瞭解

JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。java

新建測試類:
public class Dog implements Animal  {

    private String name;

    String color;

    @Override
    public void say() {
        System.out.println("dog..say..");
    }

    public void run(){
        System.out.println("dog..run..");
    }

    public void eat(String S){
        System.out.println("dog..eat.."+S);
    }


    //....

    public Dog() {
    }

    public Dog(String name, String color) {
        this.name = name;
        this.color = color;
    }
}

第一步:理解class類

1.Class是一個類,封裝了當前對象所對應的類的信息
2.一個類中有屬性,方法,構造器等,好比說有一個Person類,一個Order類,這些都是不一樣的類,如今須要一個類,用來描述類,這就是Class,
它應該有類名,屬性,方法,構造器等。Class是用來描述類的類。
3.對於每一個類而言,JRE 都爲其保留一個不變的 Class 類型的對象。
4.Class 對象只能由系統創建對象,一個類(而不是一個對象)在 JVM 中只會有一個Class實例。bootstrap

@Test
    public void test5(){
        Class clazz1=Dog.class;
        Class clazz2=Dog.class;
        System.out.println(clazz1);
        System.out.println(clazz2);
        System.out.println(clazz1==clazz2);//true
    }

獲取Class對象的三種方式
1.經過類名獲取      類名.class    
Class clazz=Dog.class;
2.經過對象獲取      對象名.getClass()
Dog dog=new Dog();
Class clazz=dog.getClass();
3.經過全類名獲取    Class.forName(全類名)    
Class clazz=Class.forName("com.utils.Dog");數組

Class類的經常使用方法:ide

方法名函數

功能說明工具

static Class forName(String name)測試

返回指定類名 name 的 Class 對象ui

Object newInstance()this

調用缺省構造函數,返回該Class對象的一個實例spa

Object newInstance(Object []args)

調用當前格式構造函數,返回該Class對象的一個實例

getName()

返回此Class對象所表示的實體(類、接口、數組類、基本類型或void)名稱

Class getSuperClass()

返回當前Class對象的父類的Class對象

Class [] getInterfaces()

獲取當前Class對象的接口

ClassLoader getClassLoader()

返回該類的類加載器

Class getSuperclass()

返回表示此Class所表示的實體的超類的Class

 第二步:ClassLoader

類裝載器是用來把類(class)裝載進 JVM 的。JVM 規範定義了兩種類型的類裝載器:啓動類裝載器(bootstrap)和用戶自定義裝載器(user-defined class loader)。 JVM在運行時會產生3個類加載器組成的初始化加載器層次結構。

 

 

第三步:反射概述


Reflection(反射)是Java被視爲動態語言的關鍵,反射機制容許程序在執行期藉助於Reflection API取得任何類的內部信息,並能直接操做任意對象的內部屬性及方法。
Java反射機制主要提供瞭如下功能:
在運行時構造任意一個類的對象
在運行時獲取任意一個類所具備的成員變量和方法
在運行時調用任意一個對象的方法(屬性)
生成動態代理

1.獲取對象中的method
    public  void test() throws Exception {

        //獲取Dog.class的對象
        Class dogClass=Dog.class;

        //獲取Dog.class全部的方法,包括父類方法,不包括私有方法
        //Method[] methods=dogClass.getDeclaredMethods();

        //獲取Dog.class全部的方法,包括私有方法,不包括父類方法
        Method[] methods=dogClass.getDeclaredMethods();
        for(Method method:methods){
            System.out.println(method.getName());
        }

        //返回該Class對象的一個實例
        Object objects= dogClass.newInstance();

        //獲取無參方法 say( )
        Method method=dogClass.getDeclaredMethod("say");

        //第一個參數表示執行哪一個對象的方法,剩下的參數是執行方法時須要傳入的參數
        method.invoke(objects,null);

        //獲取帶參方法 eat( ),參數類型爲String.class
        method=dogClass.getDeclaredMethod("eat",String.class);

        method.invoke(objects,"骨頭");

    }

 

2.獲取對象中的field
  
    public void test() throws Exception{

        Class clazz=Dog.class;

        //獲取全部字段屬性,包括私有,不包括繼承
        Field fields[]= clazz.getDeclaredFields();
        for (Field field:fields){
            System.out.println(field.getName()+"---"+field.getType());
        }

        //獲取全部繼承字段屬性
        fields = clazz.getFields();
        for (Field field:fields){
            System.out.println(field.getName()+"---"+field.getType());
        }

        //獲取非私有字段屬性
        Field field=clazz.getDeclaredField("color");
        Object object=new Dog();
        //設置字段屬性值
        field.set(object,"red");
        System.out.println("field.get(object)="+field.get(object));

        //獲取私有字段屬性
        field=clazz.getDeclaredField("name");
        object=new Dog();
        field.setAccessible(true);
        //設置字段屬性值
        field.set(object,"tom");
        System.out.println("field.get(object)="+field.get(object));
    }

 

3.獲取對象的構造方法
    public void test() throws Exception{

        Class clazz=Dog.class;

        //獲取全部構造函數
        Constructor[] constructors= clazz.getConstructors();
        for (Constructor constructor:constructors){
            System.out.println(constructor);
        }

        //獲取無參構造方法
        Constructor constructor= clazz.getConstructor(new Class[]{});
        System.out.println("無參構造 "+constructor);

        constructor=clazz.getConstructor(new Class[]{String.class,String.class});
        System.out.println("帶參構造 "+constructor);
    }

 

5.看到這裏,咱們本身動手設計一個工具方法。 
    //自定義反射方法  類對象和類方法名做爲參數,執行方法
    public Object myInvoke(Class object,String methodName,Object...args) throws Exception, InstantiationException {

        //把參數轉化爲對應的class對象
        Class[] argsClass=new Class[args.length];
        for (int i=0;i<args.length;i++){
            argsClass[i]=args[i].getClass();
            System.out.println(argsClass[i]);
        }

        //獲取方法
        Method method=object.getDeclaredMethod(methodName,argsClass);

        //執行方法
        return  method.invoke(object.newInstance(),args);
    }

測試:
 public void test() throws Exception {
        Object args[]=new Object[]{};
        Object result= myInvoke(Dog.class,"say",args);
        System.out.println("result="+result);
    }

 

6.咱們再設計一個工具方法,不但能訪問當前類的私有方法,還要能訪問父類的私有方法
通常使用getDeclaredMethod獲取方法(由於此方法能夠獲取類的私有方法,可是不能獲取父類方法),如何獲取父類方法呢?
    public Method getMethodForClass(Class clazz,String methodName,Class[] parameterTypes) throws NoSuchMethodException {

        for(;clazz != Object.class; clazz = clazz.getSuperclass()){
            try {
                Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
                if(method==null){
                    continue;
                }
                return method;
            } catch (Exception e) {
                System.out.println(e);
            }
        }

        return clazz.getDeclaredMethod(methodName, parameterTypes);
    }

 

第四步:文章小結 1. Class: 是一個類; 一個描述類的類.封裝了描述方法的 Method,描述字段的 Filed,描述構造器的 Constructor 等屬性.   2. 如何獲得 Class 對象: 2.1 Person.class 2.2 person.getClass() 2.3 Class.forName("com.atguigu.javase.Person")    3. 關於 Method: 3.1 如何獲取 Method: 1). getDeclaredMethods: 獲得 Method 的數組. 2). getDeclaredMethod(String methondName, Class ... parameterTypes)    3.2 如何調用 Method 1). 若是方法是 private 修飾的, 須要先調用 Method 的 setAccessible(true), 使其變爲可訪問 2). method.invoke(obj, Object ... args);    4. 關於 Field: 4.1 如何獲取 Field: getField(String fieldName) 4.2 如何獲取 Field 的值:  1). 若是Field是 private 修飾的, 須要先調用 Field 的 setAccessible(true),setAccessible(true) 2). field.get(Object obj) 4.3 如何設置 Field 的值: field.set(Obejct obj, Object val)    5. 瞭解 Constructor    

相關文章
相關標籤/搜索