什么是java反射機制?
? 回顧之前java程序如何使用類
? ? 1.分析,確定類名,屬性名,方法......創建類
? ? 2.創建類的對象
? ? 3.使用
一切都是已知的。
在程序開發中,在哪兒需要使用哪個類的對象,就在那兒創建這個類對象,去使用即可
這種寫法對于業務開發來說是沒問題的。
但~是!,在一些組件 或者 在框架的開發中,他們本身時不知道要處理哪些類
例如:jackson組件,我們給他什么類,他們就處理轉換什么類
new ObjectMapper().writeValueAsString(result)
在web.xml中配置了哪些servlet類,tomcat就要創建哪些類對象
<servlet-class>com.skw.dorm.web.LoginServlet</servlet-class><servlet-class>com.skw.dorm.web.TestServlet</servlet-class>
在mybatis中,給了什么類型,mybatis就可以將結果封裝映射到給定的類的對象中
<select id="findAdminById" parameterType="int" resultType="Admin">
等等一系列,這樣單一對著一個明確的類去使用。
問題:如果僅僅知道一個類的類名,能否動態得到類的定義信息,包括哪些方法, 屬性等?
以前已知類名的使用方式,可以看做是正向使用類。
而框架需要只寫一套程序,就可以處理我們給他的任意類
框架需要對任意類處理時,只是知道類的名字,通過類的名字動態才去獲取類中的信息。
把這種對類的使用方式,稱為反向使用。也可以被稱為:反射!
反射
? 概念:
? ? Java反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取信息以及動態調用對象的方法的功能稱為java語言的反射機制。
? ? Java反射機制的作用就是:可動態的獲取類的信息
? 要如何去實現Java的反射機制呢?
? ? 首先了解Java反射相關的API:
????????Java反射相關的類主要包括
? ? ? ? ????????Class 類型
????????????????Constructor 構造方法
????????????????Method 方法
????????????????Field 屬性
????????除了Class外,其他類都位于java.lang.reflect包中
????????可見,反射API將類的類型、方法、屬性都封裝成了類,其中最重要的類是 Class,可以說,反射的使用都是從Class開始。
? ? 1、Class類
????????java.lang.Class
????????一旦class文件被加載到內存,就會為其創建一個Class對象。任何類被使用時都會創建一個Class對象。
????????Class類是Java反射機制的基礎,通過Class類,可以得到一個類的基本信息。
Class類的對象,表示當前正在運行中的類和接口。
獲得Class的三種方法
要使用Class類的方法,必須先獲得該類的Class類的實例,獲得Class 類實例的常用方法有如下三種
//方式1:通過類的名稱(包名+類名)來獲取Class類Class clazz1 = Class.forName(classname);System.out.println(clazz1);
//方式2:通過只知道類來獲取Class類Class clazz2 = User.class;
//方式3:通過知道類的對象來獲取Class類User user = new User();Class clazz3 = user.getClass();
Class類的常用方法
方法名 | 功能說明 |
---|---|
static Class forName(String name) | 返回指定類名?name ?的?Class ?對象 |
Object newInstance() | 調用缺省構造函數,返回該Class 對象的一個實例 |
getName() | 返回此Class對象所表示的實體(類、接口、數組類、基本類型或void )名稱 |
Class [] getInterfaces() | 獲取當前Class 對象的接口 |
Constructor[] getConstructors() | 返回一個包含某些Constructor 對象的數組 |
Field[] getDeclaredFields() | 返回Field 對象的一個數組 |
Method getMethod(String name,Class … paramTypes) | 返回一個Method 對象,此對象的形參類型為paramType |
2、Constructor 構造方法
//使用反射機制時,只知道類的名稱(包名+類名)String classname = "com.ffyc.javareflect.User";//1.通過類名,獲得到類的Class對象Class aClass = Class.forName(classname);//2.通過類的Class對象,創建對象Object obj = aClass.newInstance();//獲得類中的構造方法,通過構造方法api中的方法創建對象Constructor constructor1 = aClass.getConstructor(); //獲得指定的公共構造方法Object obj1 = constructor1.newInstance();//無參構造方法Constructor constructor2 = aClass.getConstructor(String.class,String.class);Object obj2 = constructor2.newInstance("張三","1111");//有參構造方法System.out.println(obj1);System.out.println(obj2);Constructor[] constructors = aClass.getConstructors();//獲得所有公共的構造方法//雖然可以獲取私有構造方法,但是一般不建議操作私有成員,因為打破了封裝性aClass.getDeclaredConstructor();//獲得類中任意的構造方法,包含私有的
????????????????? ? ? ? ?
3、Method 方法
//使用反射機制時,只知道類的名稱(包名+類名)String classname = "com.ffyc.javareflect.User";//1.通過類名,獲得到類的Class對象Class aClass = Class.forName(classname);//2.通過類的Class對象,創建對象Object obj = aClass.newInstance();//獲得類中指定名稱的成員方法Method method = aClass.getMethod("eat" );//調用訪問method.invoke(obj);
?????????????????????????????????? ???????? ? ? ???????????
4、Field 屬性
//使用反射機制時,只知道類的名稱(包名+類名)String classname = "com.ffyc.javareflect.User";//1.通過類名,獲得到類的Class對象Class aClass = Class.forName(classname);//2.通過類的Class對象,創建對象Object obj = aClass.newInstance();//獲得類中成員變量//Field accountField = aClass.getField("account");//獲得指定名稱的公共的成員變量Field accountField = aClass.getDeclaredField("account");//獲得指定名稱的成員變量,包含私有的accountField.setAccessible(true);//設置允許直接訪問操作私有成員accountField.set(obj,"admin");System.out.println(obj);
???????????????? ? ? ? ? ?
模擬框架拿任意一個類的信息
//使用反射機制時,只知道類的名稱(包名+類名)String classname = "com.ffyc.javareflect.User";//1.通過類名,獲得到類的Class對象Class aClass = Class.forName(classname);//2.通過類的Class對象,創建對象Object obj = aClass.newInstance();//演示通過屬性的get和set方法,對類中私有屬性進行賦值取值操作//模擬從數據庫中查詢到的數據HashMap<String,String> map = new HashMap<>();map.put("account", "admin");map.put("password", "1111");//先拿到類中所有的私有屬性Field[] declaredFields = aClass.getDeclaredFields();for (Field field : declaredFields){//根據屬性名,生成Set方法名稱String setmethod = "set"+field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);//通過Class對象,獲得對應的Set方法對象Method setmethodobj = aClass.getMethod(setmethod,field.getType());//調用Set方法setmethodobj.invoke(obj, map.get(field.getName()));}System.out.println(obj);
??????????????????????????????????????
模擬一個簡單的json轉換格式
public class JsonUtil {public static String objectToJson(Object object) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class aclass = object.getClass();Field[] declaredFields = aclass.getDeclaredFields();String json = "{";for (Field field : declaredFields){//根據屬性名,生成Get方法名稱String getmethod = "get"+field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);//通過Class對象,獲得對應的Get方法對象Method getmethodobj = aclass.getMethod(getmethod);//調用Get方法json += field.getName() +":"+ (String) getmethodobj.invoke(object) + ",";}json = json.substring(0, json.length() - 1) + "}";return json;}public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {User user = new User();user.setAccount("admin");user.setPassword("1111");Car car = new Car();car.setName("寶馬");car.setColor("紅色");System.out.println(JsonUtil.objectToJson(user));System.out.println(JsonUtil.objectToJson(car));}
}
????????????????????????????????????????????????????????????? ? ??
反射的優缺點:
? ? 優點:
? ? ? ? ? ? 1、增加程序的靈活性,可以在運行的過程中動態對類進行修改和操作
? ? ? ? ? ? 2、提高代碼的復用率
? ? ? ? ? ? 3、可以在運行時輕松獲取任意一個類的方法、屬性,并且還能通過反射進行動態調用
? ? 缺點:
? ? ? ? ? ? 1、反射會涉及到動態類型的解析,導致性能要比非反射調用更低
? ? ? ? ? ? 2、使用反射技術通常要在一個沒有安全限制的程序運行.
? ? ? ? ? ? 3、反射可以繞過一些限制訪問的屬性或者方法,可能會導致破壞代碼本身的封裝性