一、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一下,哦啟動一下服務器!(這是傻子干的)
正確用法:
二、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); }