java筆記(一)java的反射機制

前言

java反射機制指的是在java運行過程中,對于任意的類都可以知道他的所有屬性以及方法,對于任意一個對象都可以任意的調(diào)用他的屬性和方法,這種動態(tài)獲取對象信息和動態(tài)調(diào)用對象方法的功能稱為java反射機制,但是反射使用不當會造成很高的成本。

簡單實例


反射獲取類名稱

package top.crosssoverjie.study;
public class Reflect {
    public static void main(String[] args) {
        Class<Reflect> c1 = Reflect.class;
        System.out.println(c1.getName());
        
        Reflect r1 = new Reflect() ;
        Class<Reflect> c2 = (Class<Reflect>) r1.getClass() ;
        System.out.println(c2.getName());
        
        try {
            Class<Reflect> c3 = (Class<Reflect>) Class.forName("top.crosssoverjie.study.Reflect");
            System.out.println(c3.getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

輸出結(jié)果:

top.crosssoverjie.study.Reflect
top.crosssoverjie.study.Reflect
top.crosssoverjie.study.Reflect  

以上的 c1,c2,c3是完全一樣的,他們都有一個統(tǒng)一的名稱:叫做Reflect類的類類型。


反射的用處

獲取成員方法

public Method getDeclaredMethod(String name,Class<?>...parameterTypes)//得到該類的所有方法,但是不包括父類的方法。
public Method getMethod(String name,Class<?>...parameterTypes)//獲得該類的所有public方法,包括父類的。

通過反射獲取成員方法調(diào)用的實例:

package top.crosssoverjie.study;

import java.lang.reflect.Method;

public class Person {
    private String name="crossover" ;
    private String msg ;
    
    public Person(String name, String msg) {
        this.name = name;
        this.msg = msg;
        System.out.println(name+"的描述是"+msg);
    }

    public Person() {
        super();
    }

    public void say(String name ,String msg){
        System.out.println(name+"說:"+msg);
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    
    public static void main(String[] args) {
        try {
            //首先獲取類類型
            Class c1 = Class.forName("top.crosssoverjie.study.Person") ;
            
            //通過newInstance()方法生成一個實例
            Object o1 = c1.newInstance() ;
            
            //獲取該類的say方法
            Method m1 = c1.getMethod("say", String.class,String.class) ;
            
            //通過invoke方法調(diào)用該方法
//            m1.invoke(o1, "張三","你好啊") ;
            
            Method[] methods = c1.getDeclaredMethods() ;
//            for(Method m : methods){
//                System.out.println(m.getName());
//            }
            
            Method[] methods2 = c1.getMethods() ;
            for (Method method : methods2) {
                System.out.println(method.getName());
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

輸出結(jié)果:

張三說:你好啊

所以我們只要知道類的全限定名就可以任意的調(diào)用里面的方法。


Method[] methods = c1.getDeclaredMethods() ;
for(Method m : methods){
    System.out.println(m.getName());
}

輸出結(jié)果:

main
getName
setName
say
getMsg
setMsg

使用的還是之前那個Person類,所以這里只寫了關鍵代碼。這里輸出的是Person的所有public方法。

如果我們調(diào)用getMethods()方法會是什么結(jié)果呢?

Method[] methods2 = c1.getMethods() ;
for (Method method : methods2) {
    System.out.println(method.getName());
}

輸出結(jié)果:

main
getName
setName
say
getMsg
setMsg
wait
wait
wait
hashCode
getClass
equals
toString
notify
notifyAll

這時我們會發(fā)現(xiàn)這里輸出的結(jié)果會比剛才多得多,這時因為getMethods()方法返回的是包括父類的所有方法。


獲取成員變量

我們還可以通過反射來獲取類包括父類的成員變量,主要方法如下:

public Field getDeclaredFiled(String name)//獲得該類所有的成員變量,但不包括父類的。
public Filed getFiled(String name)//獲得該類的所有的public變量,包括其父類的。

還是按照之前例子中的Person類舉例,他具有兩個成員變量:

    private String name="crossover" ;
    private String msg ;

我們可以通過以下方法來獲取其中的成員變量:

Class c1 = Class.forName("top.crosssoverjie.study.Person") ;
Field field = c1.getDeclaredField("name");//獲取該類所有的成員屬性

通過以下例子可以獲取指定對象上此field的值:

package top.crosssoverjie.study;

import java.io.File;
import java.lang.reflect.Field;

public class Reflect {
    public static void main(String[] args) {
        try {
            Class c1 = Class.forName("top.crosssoverjie.study.Person");
            Field field = c1.getDeclaredField("name") ;
            Object o1 = c1.newInstance() ;
            /**
             * 由于Person類中的name變量是private修飾的,
             * 所以需要手動開啟允許訪問,是public修飾的就不需要設置了
             */
            field.setAccessible(true);
            Object name = field.get(o1) ;
            System.out.println(name);
        } catch (Exception e) {
            e.printStackTrace() ;
        }
//        Class<Reflect> c1 = Reflect.class;
//        System.out.println(c1.getName());
//        
//        Reflect r1 = new Reflect() ;
//        Class<Reflect> c2 = (Class<Reflect>) r1.getClass() ;
//        System.out.println(c2.getName());
//        
//        try {
//            Class<Reflect> c3 = (Class<Reflect>) Class.forName("top.crosssoverjie.study.Reflect");
//            System.out.println(c3.getName());
//        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
//        }
    }
}

輸出結(jié)果:

crossover

我們也可以通過方法getDeclaredFieds()方法來獲取所有的成員變量,返回是是一個Field[]數(shù)組,只需要遍歷這個數(shù)組即可獲所有的成員變量。例子如下:

Field[] fields = c1.getDeclaredFields() ;
for(Field f :fields){
    System.out.println(f.getName());
}

輸出結(jié)果如下:

name
msg

獲取構造方法

可以通過以下兩個方法來獲取構造方法:

public Constructor getDeclaredConstructor(Class<?>...parameterTypes)//獲取該類的所有構造方法,不包括父類的。
public Constructor getConstructor(Class<?>...parameterTypes)//獲取該類的所有public修飾的構造方法,包括父類的。

在之前的Person類中有以下的構造方法:

    public Person(String name, String msg) {
        this.name = name;
        this.msg = msg;
    }

我們可以通過以下方法來獲取Person類的構造方法:

Constructor dc1 = c1.getDeclaredConstructor(String.class,String.class) ;

具體代碼如下:

    Constructor dc1 = c1.getDeclaredConstructor(String.class,String.class) ;
    dc1.setAccessible(true);
    dc1.newInstance("小明","很帥") ;

dc1.newInstance("小明","很帥");方法調(diào)用了Person類中的:

    public Person(String name, String msg) {
        this.name = name;
        this.msg = msg;
        System.out.println(name+"的描述是"+msg);
    }

這個構造方法,如果不傳參數(shù)的話,那么調(diào)用的就是無參的構造方法。輸出結(jié)果為:

小明的描述是很帥

通過反射了解集合泛型的本質(zhì)

通過以下例子程序可以看出:

package top.crosssoverjie.study;

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

public class GenericEssence {
    public static void main(String[] args) {
        //聲明兩個list,一個有泛型,一個沒有泛型
        List list1 = new ArrayList() ;
        List<String> list2 = new ArrayList<String>() ;
        
        list2.add("你好") ;
//        list2.add(11) ;加上泛型之后在編譯期間只能添加String,不然會報錯。
        System.out.println("list2的長度是:"+list2.size());
        
        
        Class c1 = list1.getClass();
        Class c2 = list2.getClass() ;
        System.out.print("c1,c2是否相等:");
        System.out.println(c1==c2);
        
        try {
            //通過反射繞過編譯器動態(tài)調(diào)用add方法,可能否加入非String類型的元素
            Method method = c2.getDeclaredMethod("add", Object.class) ;
            method.invoke(list2, 123) ;//在這里加入int類型,在上面如果加入int會出現(xiàn)編譯報錯。
            
            //list2的長度增加了,說明添加成功了
            System.out.println("現(xiàn)在list2的長度是:"+list2.size());
            
            /**
             * 所以可以看出,泛型只是在編譯期間起作用,在經(jīng)過編譯進入運行期間是不起作用的。
             * 就算是不是泛型要求的類型也是可以插入的。
             */
            
        } catch (Exception e) {
            e.printStackTrace() ;
        }
        
    }
}

所以可以看出,泛型只是在編譯期間起作用,在經(jīng)過編譯進入運行期間是不起作用的。就算是不是泛型要求的類型也是可以插入的。

反射知識點

泛型

總結(jié)

泛型的應用比較多:

  • spring的IOC/DI。
  • JDBC中的中的加載驅(qū)動

參考

個人博客地址:http://crossoverjie.top。
GitHub地址:https://github.com/crossoverJie。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 20- 枚舉,枚舉原始值,枚舉相關值,switch提取枚舉關聯(lián)值 Swift枚舉: Swift中的枚舉比OC中的枚...
    iOS_恒仔閱讀 2,428評論 1 6
  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,812評論 0 11
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內(nèi)部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,673評論 18 399
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,256評論 0 62
  • 手工課上的布娃娃我只把輪廓從布上剪下來,再縫了小兔子布娃娃的左耳朵,下星期四就要展覽了,這個周末必須做完這...
    袁名緣閱讀 653評論 0 0

友情鏈接更多精彩內(nèi)容