Java反射的理解


一、Java內存模型 

先了解一下JVM(虛擬機),java之所以能跨平台就是因為這個東西,你可以理解成一個進程,程序,只不過他的作用是用來跑你的代碼的。

假如你寫了一段代碼:Object o=new Object();

運行了起來!

首先JVM會啟動,你的代碼會編譯成一個.class文件,然后被類加載器加載進jvm的內存中,你的類Object加載到方法區中,創建了Object類的class對象到堆中,注意這個不是new出來的對象,而是類的類型對象,每個類只有一個class對象,作為方法區類的數據結構的接口。jvm創建對象前,會先檢查類是否加載,尋找類對應的class對象,若加載好,則為你的對象分配內存,初始化也就是代碼:new Object()。

上面的流程就是你自己寫好的代碼扔給jvm去跑,跑完就over了,jvm關閉,你的程序也停止了。

 

為什么要講這個呢?因為要理解反射必須知道它在什么場景下使用。

題主想想上面的程序對象是自己new的,程序相當於寫死了給jvm去跑。假如一個服務器上突然遇到某個請求哦要用到某個類,哎呀但沒加載進jvm,是不是要停下來自己寫段代碼,new一下,哦啟動一下服務器!(這是傻子干的)

正確用法:

當我們的程序在運行時,需要動態的加載一些類這些類可能之前用不到所以不用加載到jvm,而是在運行時根據需要才加載,這樣的好處對於服務器來說不言而喻,舉個例子我們的項目底層有時是用mysql,有時用oracle,需要動態地根據實際情況加載驅動類,這個時候反射就有用了,假設 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection這兩個類我們要用,這時候我們的程序就寫得比較動態化,通過Class tc = Class.forName("com.java.dbtest.TestConnection");通過類的全類名讓jvm在服務器中找到並加載這個類,而如果是oracle則傳入的參數就變成另一個了。這時候就可以看到反射的好處了,這個動態性就體現出java的特性了!舉多個例子,大家如果接觸過spring,會發現當你配置各種各樣的bean時,是以配置文件的形式配置的,你需要用到哪些bean就配哪些,spring容器就會根據你的需求去動態加載,你的程序就能健壯地運行。
 
 

二、Java反射機制

含義:所謂的反射機制就是java語言在運行時擁有一項自觀的能力。通過這種能力可以徹底的了解自身的情況為下一步的動作做准備。 

Java的反射機制的實現要借助於4個類:class,Constructor,Field,Method。

Java反射的作用:在Java運行時環境中,對於任意一個類,可以知道這個類有哪些屬性和方法。對於任意一個對象,可以調用它的任意一個方法。這種動態獲取類的信息以及動態調用對象的方法的功能來自於Java 語言的反射(Reflection)機制。

Java 反射機制主要提供了以下功能:

在運行時判斷任意一個對象所屬的類。
在運行時構造任意一個類的對象。
在運行時判斷任意一個類所具有的成員變量和方法。
在運行時調用任意一個對象的方法


三、Java反射用法

1、獲取類對象的方法

 Class<?> cl = Class.forName("java.lang.String");
Class<?> cl = String.class;
String str = "111";
Class<?> cl = str.getClass

2.獲取字段信息的方法

Class<?> cl = String.class;
//獲取公有的指定成員變量(包括繼承的公有變量都能訪問到但是私有和受保護的屬性訪問不到)
Field field = cls.getField("變量名");
//獲取公有所有成員變量(私有的和受保護的訪問不到)
Field[] fields = cls.getFields();
//獲取以聲明的指定變量(私有、公有、受保護的都能訪問到,但是不包括繼承的) 
Field field1 = cls.getDeclaredField("變量名");
//獲取所有以聲明的變量
 Field[] fields1 = cls.getDeclaredFields();

3、獲取方法信息的方法

 //返回某個類的指定的公用(public)方法,包括其繼承類的公用方法。
Method method = cl.getMethod("方法名");
//返回某個類的所有公用(public)方法.
Method[] methods = cl.getMethods();
//返回類或接口聲明的指定方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。可以傳方法名和方法的參數類型,多個參數逗號隔開。
Method method = cl.getDeclaredMethod("方法名", String.class);
//返回類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。
Method[] methods = c.getDeclaredMethods();

4、獲取構造器的方法

//獲取該Class對象公有的使用特殊參數類型的構造函數,與父類構造無關
Constructor<?> constructor = cl.getConstructor(參數類型);
//獲取該Class對象所有公有的構造函數
 Constructor[] constructors = c.getConstructors();
//獲取該Class對象指定的聲明的構造函數包括公有、私有、受保護的,與父類構造無關
Constructor<?> constructor1 = c.getDeclaredConstructor(參數類型)
//獲取該Class對象所有聲明的構造函數
Constructor[] constructors1 = c.getDeclaredConstructors();

 

四、總結

當我們用getDeclaredField("變量名")獲取到聲明指定變量時,直接修改該屬性的值時,需要調用field.setAccessible(true),這時才能修改該變量的值,因為該變量可能是私有的或者是受保護的不允許直接修改,而當我們這樣做了就違背了java面向對象封裝的原則,並且在有些業務上當你不了解有些私有屬性不能被修改時,你就可以通過反射獲取該類的所有set方法,通過調用set方法去改變具體屬性值。

 

這個是用來將字符串首字母轉大寫的方法,進行字母的ascii編碼前移

//將傳進來的字段名首字母大寫
    private static String getMethodName(String fildeName) throws Exception{
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }

 

 

大神們這些都是個人理解哪里有一樣的想法或建議歡迎評論!!!!!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM