反射——Java高級開發必備知識

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

本文主要記錄Class類的使用,方法和成員變量的反射,以及經過反射了解集合泛型的本質等知識。函數

Class類

Java程序在運行的時候,系統始終爲全部的對象維護一個被稱爲運行時的類型標誌。這個對象跟蹤着每一個對象所屬的類。Java虛擬機利用運行時類型信息選擇相應的方法運行。保存這些信息的類被稱爲Class。code

  • 在面向對象的世界裏,一切皆對象。

類是對象,類是java.lang.Class類的實例對象。對象

  • 這個對象如何表示?

有3種表示方式:繼承

第一種方式:Foo.class,實際上在告訴咱們任何一個類都有一個隱含的靜態成員變量class;開發

第二種方式:已知該類的對象,經過getClass()方法get

第三種方式:Class.forName("全路徑")虛擬機

package com.imooc.reflect;

public class ClassDemo1{
    public static void main(String[] args){
        //Foo的實例對象如何表示
        Foo foo1 = new Foo();
        
        //Foo這個類也是一個實例對象,Class類的實例對象
        //任何一個類都是Class類的實例對象,這個實例對象有3中表示方式。
        
        //第一種表示方式-->實際上在告訴咱們任何一個類都有一個隱含的靜態成員變量
        Class c1 = Foo.class;
        
        //第二種方式,已知該類的對象,經過getClass()方法
        Class c2 = foo1.getClass();
        
        //c1,c2表示了Foo類的類類型(class type)
        //無論c1仍是c2都表明了Foo類的類類型。一個類只多是Class類的一個實例對象
        System.out.println(c1 == c2);
        
        //第三種表達方式
        Class c3 = null;
        try{
            c3 = Class.forName("com.imooc.reflect.Foo");
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }
        System.out.println(c2 == c3);
        
        //咱們徹底能夠經過類的類類型建立該類的對象實例-->經過c1或者c2或者c3建立Foo的實例對象
        try{
            Foo foo = (Foo)c1.newInstance();//須要有無參數的構造方法
        }catch(InstantiationException e){
            e.printStackTrace();
        }
    }
}
class Foo{}

動態加載類

Class.forName("com.imooc.reflect.Foo");string

不只表示了類的類類型,還表明了動態加載類io

區分編譯、運行:

編譯時刻加載類是靜態加載類、運行時刻加載類是動態加載類。

功能性的類使用動態加載。

獲取方法信息

基本的數據類型、void關鍵字都存在類類型。

package com.imooc.reflect;

public class ClassDemo2{
    public static void main(String[] args){
        Class c1 = int.class;//int的類類型
        Class c2 = String.class;//String類的類類型,
        Class c3 = void.class;
    }
}

Class類的基本API

java.lang.reflect包中的Method用於描述類的方法。

getName返回方法的名稱;

package com.imooc.reflect;

public class ClassUtil{
    
    /**
     * 打印類的信息,包括類的成員函數、成員變量(只獲取成員函數)
     * @param obj 該對象所屬類的信息
     */
    public static void printClassMethodMessage(Object obj){
        //要獲取類的信息  首先要獲取類的類類型
        Class c = obj.getClass();//傳遞的是哪一個子類的對象  c就是該子類的類類型
        //獲取類的名稱
        System.out.println("類的名稱是:"+c.getName());
        /*
         * Method類,方法對象
         * 一個成員方法就是一個Method對象
         * getMethods()方法獲取的是全部的public的函數,包括父類繼承而來的
         * getDeclaredMethods()獲取的是全部該類本身聲明的方法,不問訪問權限
         */
        Method[] ms = c.getMethods();//c.getDeclaredMethods()
        for(int i = 0; i < ms.length;i++){
            //獲得方法的返回值類型的類類型
            Class returnType = ms[i].getReturnType();
            System.out.print(returnType.getName()+" ");
            //獲得方法的名稱
            System.out.print(ms[i].getName()+"(");
            //獲取參數類型--->獲得的是參數列表的類型的類類型
            Class[] paramTypes = ms[i].getParameterTypes();
            for (Class class1 : paramTypes) {
                System.out.print(class1.getName()+",");
            }
            System.out.println(")");
        }
    }
}

Java獲取成員變量信息

/**
     * 獲取成員變量的信息
     * @param obj
     */
    public static void printFieldMessage(Object obj) {
        Class c = obj.getClass();
        /*
         * 成員變量也是對象
         * java.lang.reflect.Field
         * Field類封裝了關於成員變量的操做
         * getFields()方法獲取的是全部的public的成員變量的信息
         * getDeclaredFields獲取的是該類本身聲明的成員變量的信息
         */
        //Field[] fs = c.getFields();
        Field[] fs = c.getDeclaredFields();
        for (Field field : fs) {
            //獲得成員變量的類型的類類型
            Class fieldType = field.getType();
            String typeName = fieldType.getName();
            //獲得成員變量的名稱
            String fieldName = field.getName();
            System.out.println(typeName+" "+fieldName);
        }
    }

獲取構造函數的信息

java.lang.reflect包中的Constructor用於描述類的構造函數。

/**
     * 打印對象的構造函數的信息
     * @param obj
     */
    public static void printConMessage(Object obj){
        Class c = obj.getClass();
        /*
         * 構造函數也是對象
         * java.lang. Constructor中封裝了構造函數的信息
         * getConstructors獲取全部的public的構造函數
         * getDeclaredConstructors獲得全部的構造函數
         */
        //Constructor[] cs = c.getConstructors();
        Constructor[] cs = c.getDeclaredConstructors();
        for (Constructor constructor : cs) {
            System.out.print(constructor.getName()+"(");
            //獲取構造函數的參數列表--->獲得的是參數列表的類類型
            Class[] paramTypes = constructor.getParameterTypes();
            for (Class class1 : paramTypes) {
                System.out.print(class1.getName()+",");
            }
            System.out.println(")");
        }
    }

方法反射的基本操做

如何獲取某個方法?

方法的名稱和方法的參數列表才能惟一決定某個方法

方法反射的操做

method.invoke(對象、參數列表)

package com.imooc.reflect;

import java.lang.reflect.Method;

public class MethodDemo1 {
    public static void main(String[] args) {
       //要獲取print(int ,int )方法  1.要獲取一個方法就是獲取類的信息,獲取類的信息首先要獲取類的類類型
        A a1 = new A();
        Class c = a1.getClass();
        /*
         * 2.獲取方法 名稱和參數列表來決定  
         * getMethod獲取的是public的方法
         * getDelcaredMethod本身聲明的方法
         */
        try {
            //Method m =  c.getMethod("print", new Class[]{int.class,int.class});
            Method m = c.getMethod("print", int.class,int.class);
            
            //方法的反射操做  
            //a1.print(10, 20);方法的反射操做是用m對象來進行方法調用 和a1.print調用的效果徹底相同
            //方法若是沒有返回值返回null,有返回值返回具體的返回值
            //Object o = m.invoke(a1,new Object[]{10,20});
            Object o = m.invoke(a1, 10,20);
            System.out.println("==================");
            //獲取方法print(String,String)
             Method m1 = c.getMethod("print",String.class,String.class);
             //用方法進行反射操做
             //a1.print("hello", "WORLD");
             o = m1.invoke(a1, "hello","WORLD");
             System.out.println("===================");
           //  Method m2 = c.getMethod("print", new Class[]{});
                Method m2 = c.getMethod("print");
               // m2.invoke(a1, new Object[]{});
                m2.invoke(a1);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
     
    }
}
class A{
    public void print(){
        System.out.println("helloworld");
    }
    public void print(int a,int b){
        System.out.println(a+b);
    }
    public void print(String a,String b){
        System.out.println(a.toUpperCase()+","+b.toLowerCase());
    }
}

經過反射了解集合泛型的本質

經過Class、Method來認識泛型的本質

package com.imooc.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class MethodDemo4 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        
        ArrayList<String> list1 = new ArrayList<String>();
        list1.add("hello");
        //list1.add(20);錯誤的
        Class c1 = list.getClass();
        Class c2 = list1.getClass();
        System.out.println(c1 == c2);
        //反射的操做都是編譯以後的操做
        
        /*
         * c1==c2結果返回true說明編譯以後集合的泛型是去泛型化的
         * Java中集合的泛型,是防止錯誤輸入的,只在編譯階段有效,
         * 繞過編譯就無效了
         * 驗證:咱們能夠經過方法的反射來操做,繞過編譯
         */
        try {
            Method m = c2.getMethod("add", Object.class);
            m.invoke(list1, 20);//繞過編譯操做就繞過了泛型
            System.out.println(list1.size());//2
            System.out.println(list1);//[hello,20]
            /*for (String string : list1) {
                System.out.println(string);
            }*///如今不能這樣遍歷
        } catch (Exception e) {
          e.printStackTrace();
        }
    }
}
相關文章
相關標籤/搜索