Java高級(jí)特性之反射學(xué)習(xí)總結(jié)
老規(guī)矩我們還是先提出幾個(gè)問(wèn)題,一門(mén)技術(shù)必然要能解決一定的問(wèn)題,才有去學(xué)習(xí)掌握它的價(jià)值
- 一、 什么是反射?
- 二、反射能做什么?
一、 什么是反射?
用在Java身上指的是我們可以于運(yùn)行時(shí)加載、探知、使用編譯期間完全未知的classes。換句話說(shuō),Java程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱(chēng)的class,獲悉其完整構(gòu)造(但不包括methods定義),并生成其對(duì)象實(shí)體、或?qū)ζ鋐ields設(shè)值、或喚起其methods。
如果你是一個(gè)Android Developer,前輩們都會(huì)教導(dǎo)你盡量少用反射,效率太低,太慢。“射”嘛,射的太快就不好了,所以反射雖然慢點(diǎn),但是偶爾射一下還是很”爽”的。
二、反射能做什么?
1、新建類(lèi)的實(shí)例
我們知道所有的類(lèi)都繼承子***父類(lèi)Object,而Object中有hashCode()、equals()、clone()、toString()、getClass()等。其中g(shù)etClass()返回一個(gè)Class 對(duì)象。我們這里就需要使用的Class對(duì)象,注意C是大寫(xiě),我們可以通過(guò)一下方式來(lái)獲取Class對(duì)象
- Class.forName(“類(lèi)名字符串”) (注意:類(lèi)名字符串必須是全稱(chēng),包名+類(lèi)名)
- 類(lèi)名.class
- 實(shí)例對(duì)象.getClass()
在Class類(lèi)中有一個(gè)非常重要的方法
- public T newInstance() throws InstantiationException, IllegalAccessException {
- return newInstanceImpl();
- }
- private native T newInstanceImpl() throws IllegalAccessException, InstantiationException;
查看Api可以看到調(diào)用newInstace方法可以返回當(dāng)前class對(duì)應(yīng)的實(shí)例對(duì)象。接下來(lái)看一個(gè)小的Demo
- public class Reflection {
- public static void main(String[] args) {
- // 普通創(chuàng)建類(lèi)的實(shí)例
- People p1 = new People();
- System.out.println(p1.getName());
- // 利用反射獲取類(lèi)的實(shí)例
- Class clazz = People.class;
- // 常用方式,注意括號(hào)中需要放類(lèi)的全路徑名
- // Class clazz = Class.forName("reflection.People");
- // Class clazz = p1.getClass();
- try {
- People p2 = (People) clazz.newInstance();
- System.out.println(p2.getName());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- class People {
- private String name = "張三";
- private int age;
- 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;
- }
- }
輸入結(jié)果:
- 張三
- 張三
2、獲取成員變量和方法
在講之前我們先來(lái)看這樣一個(gè)小按理,JSON數(shù)據(jù)轉(zhuǎn)JavaBaen對(duì)象,在不用解析庫(kù)的情況下,一般我們會(huì)這樣做
- private void analysisDate(JSONObject response) throws JSONException {
- int announceid = response.getInt("announceid");
- String title = response.getString("title");
- String hits = response.getString("hits");
- String addtime = response.getString("addtime");
- NewsNotifyItem newsNotifyItem = new NewsNotifyItem(announceid,
- title, hits, addtime);
- }
- }
每當(dāng)我們需要解析額時(shí)候,都需要根據(jù)不同javabean來(lái)進(jìn)行相應(yīng)的解析,我們每次進(jìn)行的操作都是一樣的,只是解析的數(shù)據(jù)不同而已,結(jié)合上篇帖子講到的泛型,這里我們就可以再利用反射來(lái)自己做一個(gè)Json解析工具。
下面是我寫(xiě)的一個(gè)JsonObject對(duì)象轉(zhuǎn)JavaBean的一個(gè)工具類(lèi),需要注意的是,JSON的key需要和字段名保持一致,先說(shuō)下思路
①首先通過(guò)反射獲取JavaBean中的所有字段值的名稱(chēng)
②拼接出set方法
③由于字段名和Json的key值相同,利用自動(dòng)名獲取Json中的值并填充的實(shí)例對(duì)象中
- public class Json2BeanUtils {
- public static <T> T jsonToBean(JSONObject response, Class<T> clazz) {
- try {
- // 創(chuàng)建類(lèi)的實(shí)例
- Object object = Class.forName(clazz.getName()).newInstance();
- // 獲取類(lèi)中的所有成員變量
- Field[] fields = object.getClass().getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- //設(shè)置權(quán)限
- fields[i].setAccessible(true);
- // 獲取字段的名稱(chēng)
- String fieldName = fields[i].getName();
- // 過(guò)濾掉UID
- if (fieldName.endsWith("serialVersionUID")) {
- continue;
- }
- // 獲取字段的類(lèi)型
- String fieldType = fields[i].getGenericType().toString();
- // 拼接出JavaBean中的set方法 這里有一個(gè)坑 后面講解
- String methodName = "set"
- + fieldName.substring(0, 1).toUpperCase()
- + fieldName.substring(1);
- try {
- // 判斷變量類(lèi)型
- if (fieldType.endsWith("class java.lang.String")) {
- // 獲取到set方法
- Method m = object.getClass().getMethod(methodName,
- String.class);
- String value = null;
- try {
- // 從JsonObj中取出相應(yīng)的值
- value = response.getString(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = "";
- }
- if (TextUtils.isEmpty(value)) {
- value = "";
- } else if (value.endsWith("null")) {
- value = "";
- }
- // 賦值
- m.invoke(object, value);
- } else if (fieldType.endsWith("int")
- || fieldType.endsWith("class java.lang.Integer")) {
- // int 類(lèi)型
- System.out.println();
- Method m = object.getClass().getMethod(methodName,
- int.class);
- int value = -1;
- try {
- value = response.getInt(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = -1;
- }
- m.invoke(object, value);
- } else if (fieldType.endsWith("boolean")
- || fieldType
- .endsWith("fieldType:class java.lang.Boolean")) {
- // boolean 類(lèi)型
- Method m = object.getClass().getMethod(methodName,
- boolean.class);
- boolean value = false;
- try {
- value = response.getBoolean(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = false;
- }
- m.invoke(object, value);
- } else if (fieldType.endsWith("double")
- || fieldType
- .endsWith("fieldType:class java.lang.Double")) {
- // double 類(lèi)型
- Method m = object.getClass().getMethod(methodName,
- double.class);
- double value = -1D;
- try {
- value = response.getDouble(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = -1D;
- }
- m.invoke(object, value);
- } else if (fieldType.endsWith("char")) {
- // char類(lèi)型 JSONObject 沒(méi)有char
- Method m = object.getClass().getMethod(methodName,
- String.class);
- String value = "";
- try {
- value = response.getString(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = "";
- }
- m.invoke(object, value);
- } else if (fieldType.endsWith("float")
- || fieldType
- .endsWith("fieldType:class java.lang.Float")) {
- // float類(lèi)型
- Method m = object.getClass().getMethod(methodName,
- double.class);
- double value = -1D;
- try {
- value = response.getDouble(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = -1D;
- }
- m.invoke(object, value);
- } else if (fieldType.endsWith("short")
- || fieldType
- .endsWith("fieldType:class java.lang.Short")) {
- // short
- Method m = object.getClass().getMethod(methodName,
- short.class);
- int value = -1;
- try {
- value = response.getInt(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = -1;
- }
- m.invoke(object, value);
- } else if (fieldType.endsWith("byte")
- || fieldType
- .endsWith("fieldType:class java.lang.Byte")) {
- Method m = object.getClass().getMethod(methodName,
- byte.class);
- int value = -1;
- try {
- value = response.getInt(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = -1;
- }
- m.invoke(object, value);
- } else if (fieldType.endsWith("long")
- || fieldType
- .endsWith("fieldType:class java.lang.Long")) {
- Method m = object.getClass().getMethod(methodName,
- long.class);
- Long value = -1L;
- try {
- value = response.getLong(fieldName);
- } catch (Exception e) {
- e.printStackTrace();
- value = -1L;
- }
- m.invoke(object, value);
- }
- } catch (Exception e) {
- // TODO: handle exception
- }
- }
- return (T) object;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- }
這里需要注意一個(gè)坑,先來(lái)看一段代碼
- class People {
- private String name;
- private int age;
- private String mSex;
- 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;
- }
- public String getmSex() {
- return mSex;
- }
- // 這里就出了問(wèn)題
- public void setmSex(String mSex) {
- this.mSex = mSex;
- }
- }
當(dāng)我們自動(dòng)生成get set方法時(shí),會(huì)將字段的首字母大寫(xiě),我們?cè)谏厦嫫唇觭et 方法時(shí),也是基于這樣的規(guī)則來(lái)拼裝的。但是 當(dāng)我們的字段名為 aAbbb 時(shí),則生成的get set 方法則不會(huì)大寫(xiě)。解決方案也很簡(jiǎn)單,注意字段命名或者在拼接時(shí)對(duì)第二個(gè)自動(dòng)進(jìn)行大小寫(xiě)判斷。這樣我們自己寫(xiě)的Json解析工具就搞定, 以后每次解析只需一行代碼即可OK。