咱們知道JAVA中一個比較重要的特性就是反射機制,那麼反射到底是什麼,咱們又能用反射作些什麼呢?今天咱們就來一探究竟。java
反射:將類的各個組成部分封裝爲其餘對象,這就是反射機制。框架
反射的做用:函數
一、在程序運行時操做這些對象;this
應用示例:IDEA中定義一個list對象,在使用「list.」時,會彈出對應的方法,這個就是利用反射,在IDEA運行時,就能知道對象list的成員方法;
編碼
二、能夠解耦,提升程序的可擴展性;spa
講到這裏,咱們可能還很迷惑,JAVA的反射機制到底是什麼?在進行下面的講解前,咱們先了解一下JAVA代碼在計算機中的三個階段,來幫助咱們理解反射機制。code
一、第一個階段:源代碼階段也就是咱們寫的JAVA代碼,經過編譯器編譯成字節碼文件這個過程,咱們寫的類含有成員變量,構造方法,成員方法;對象
二、第二個階段:類加載器將咱們的字節碼文件加載到內存,生成Class類對象(Class類封裝一個對象和接口運行時的狀態,當裝載類時,Class類型的對象自動建立)。反射定義中的」封裝爲其餘對象「,這裏的對象即是指,成員變量封裝爲Filed對象,構造方法封裝爲Constructor對象以及成員方法封裝爲Method對象;blog
三、第三個階段:該階段就能夠建立對象和調用對象裏的方法。經過new Student()建立對象。接口
JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。簡單來講就是獲得Class對象後反向獲取Student對象的各類信息。
對應java代碼在程序中的三個階段:
一、Class.forName("全類名"):將字節碼文件加載進內存,返回Class對象;
使用場景:多用於配置文件,將全類名配置到配置文件中,經過讀取配置文件加載類;
二、類名.class :經過類名的屬性Class獲取;
使用場景:多用於參數傳遞;
三、對象.getClass():經過類的getClass方法獲取,getClass()方法在Object類中定義,全部的類都有該方法;
使用場景:已經獲得類對象實例的狀況;
示例代碼以下:
public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public void goToSchool(){ System.out.println("go to school"); } public static void main(String[] args) throws Exception { //一、Class.forName("全類名") Class aClass = Class.forName("com.sean.Student"); System.out.println(aClass); //二、類名.class Class bClass = Student.class; System.out.println(bClass); //三、類對象.getClass() Student student = new Student(); Class cClass = student.getClass(); System.out.println(cClass); } }
PS:同一個字節碼文件(*.class),再一次程序運行中,只會被加載一次,三種方式獲取的Class類對象是同一個,能夠經過比較aClass,bClass和cClass來驗證;
下面咱們就簡單列出幾個經常使用的功能,其餘功能使用能夠參見JAVA的API文檔中的Class類。
這裏咱們建立一個Student類,便於下面咱們使用反射操做Student類對象。
public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public void goToSchool(){ System.out.println("go to school"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
方法 | 用途 |
---|---|
getField(String name) | 得到某個公有的屬性對象 |
getFields() | 得到全部公有的屬性對象 |
getDeclaredField(String name) | 得到某個屬性對象 |
getDeclaredFields() | 得到全部屬性對象 |
Filed類具體的用法能夠查看JAVA的API文檔,這裏咱們只演示了利用獲取到的Filed對象獲取以及設置成員變量的值。
public static void main(String[] args) throws Exception { Class bClass = Student.class; //獲取Student對象的全部public屬性成員變量Filed對象 Field[] fields = bClass.getFields(); for (Field field : fields) { System.out.println(field); } //獲取Student對象中name屬性成員變量,由於name爲私有,這裏會拋java.lang.NoSuchFieldException異常 Field name = bClass.getField("name"); System.out.println(name); //獲取Student對象中name屬性成員變量Filed對象 Field name1 = bClass.getDeclaredField("name"); System.out.println(name1); /** * setAccessible(true)暴力反射 * 這裏因爲name屬性是私有成員變量,不加這一句, * 後面的獲取以及設置成員變量會拋java.lang.IllegalAccessException異常 */ name1.setAccessible(true); //獲取name成員變量的值 Student student = new Student(); Object o = name1.get(student); System.out.println(o); //設置name成員變量的值 name1.set(student,"zhangsan"); System.out.println(student.getName()); }
方法 | 用途 |
---|---|
getConstructor(Class...<?> parameterTypes) | 得到該類中與參數類型匹配的公有構造方法 |
getConstructors() | 得到該類的全部公有構造方法 |
getDeclaredConstructor(Class...<?> parameterTypes) | 得到該類中與參數類型匹配的構造方法 |
getDeclaredConstructors() | 得到該類全部構造方法 |
Constructor類具體的用法能夠查看JAVA的API文檔,這裏咱們只演示了利用獲取到的Constructor對象建立Student對象。
public static void main(String[] args) throws Exception { Class bClass = Student.class; //獲取Student對象的無參構造函數Constructor對象 Constructor constructor = bClass.getConstructor(); //利用獲取到的Constructor對象建立Student對象 Object o = constructor.newInstance(); System.out.println(o); }
方法 | 用途 |
---|---|
getMethod(String name, Class...<?> parameterTypes) | 得到該類某個公有的方法 |
getMethods() | 得到該類全部公有的方法 |
getDeclaredMethod(String name, Class...<?> parameterTypes) | 得到該類某個方法 |
getDeclaredMethods() | 得到該類全部方法 |
Method類具體的用法能夠查看JAVA的API文檔,這裏咱們只演示了利用獲取到的Method對象執行執行Student類的成員方法。
public static void main(String[] args) throws Exception { Class bClass = Student.class; //獲取Student對象的goToSchool成員方法Method對象 Method goToSchool = bClass.getMethod("goToSchool"); //利用獲取到的Method對象執行Student類中的成員方法 Student student = new Student(); goToSchool.invoke(student); }
方法 | 用途 |
---|---|
getName() | 得到該類的類名 |
public static void main(String[] args) throws Exception { Class bClass = Student.class; //獲取Student對象的類名 String name = bClass.getName(); System.out.println(name); }
JAVA中有不少開源的框架(框架是半成品的軟件,能夠在框架的基礎上進行編碼),使用這些框架能極大的簡化咱們的開發過程。而反射是框架的靈魂。固然不瞭解反射咱們也可使用這些框架進行開發,但瞭解反射的機制,能讓咱們知其然,知其因此然,在使用這些框架的時候更加駕輕就熟。