Java高階特性之反射學習總結
老規矩我們還是先提出幾個問題,一門技術必然要能解決一定的問題,才有去學習掌握它的價值
- 一、 什麼是反射?
- 二、反射能做什麼?
一、 什麼是反射?
用在Java身上指的是我們可以於執行時載入、探知、使用編譯期間完全未知的classes。換句話說,Java程式可以載入一個執行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其物件實體、或對其fields設值、或喚起其methods。
如果你是一個Android Developer,前輩們都會教導你儘量少用反射,效率太低,太慢。“射”嘛,射的太快就不好了,所以反射雖然慢點,但是偶爾射一下還是很”爽”的。
二、反射能做什麼?
1、新建類的例項
我們知道所有的類都繼承子頂級父類Object,而Object中有hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一個Class 物件。我們這裡就需要使用的Class物件,注意C是大寫,我們可以通過一下方式來獲取Class物件
1.Class.forName(“類名字串”) (注意:類名字串必須是全稱,包名+類名)
2.類名.class
3.例項物件.getClass()
在Class類中有一個非常重要的方法
public T newInstance() throws InstantiationException, IllegalAccessException { return newInstanceImpl(); } private native T newInstanceImpl() throws IllegalAccessException, InstantiationException;
檢視Api可以看到呼叫newInstace方法可以返回當前class對應的例項物件。接下來看一個小的Demo
public class Reflection { public static void main(String[] args) { // 普通建立類的例項 People p1 = new People(); System.out.println(p1.getName()); // 利用反射獲取類的例項 Class clazz = People.class; // 常用方式,注意括號中需要放類的全路徑名 // 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; } }
輸入結果:
張三
張三
2、獲取成員變數和方法
在講之前我們先來看這樣一個小按理,JSON資料轉JavaBaen物件,在不用解析庫的情況下,一般我們會這樣做
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); } }
每當我們需要解析額時候,都需要根據不同javabean來進行相應的解析,我們每次進行的操作都是一樣的,只是解析的資料不同而已,結合上篇帖子講到的泛型,這裡我們就可以再利用反射來自己做一個Json解析工具。
下面是我寫的一個JsonObject物件轉JavaBean的一個工具類,需要注意的是,JSON的key需要和欄位名保持一致,先說下思路
①首先通過反射獲取JavaBean中的所有欄位值的名稱
②拼接出set方法
③由於欄位名和Json的key值相同,利用自動名獲取Json中的值並填充的例項物件中
public class Json2BeanUtils { public static <T> T jsonToBean(JSONObject response, Class<T> clazz) { try { // 建立類的例項 Object object = Class.forName(clazz.getName()).newInstance(); // 獲取類中的所有成員變數 Field[] fields = object.getClass().getDeclaredFields(); for (int i = 0; i < fields.length; i++) { //設定許可權 fields[i].setAccessible(true); // 獲取欄位的名稱 String fieldName = fields[i].getName(); // 過濾掉UID if (fieldName.endsWith("serialVersionUID")) { continue; } // 獲取欄位的型別 String fieldType = fields[i].getGenericType().toString(); // 拼接出JavaBean中的set方法 這裡有一個坑 後面講解 String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); try { // 判斷變數型別 if (fieldType.endsWith("class java.lang.String")) { // 獲取到set方法 Method m = object.getClass().getMethod(methodName, String.class); String value = null; try { // 從JsonObj中取出相應的值 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 型別 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 型別 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 型別 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型別 JSONObject 沒有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型別 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; } }
這裡需要注意一個坑,先來看一段程式碼
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; } // 這裡就出了問題 public void setmSex(String mSex) { this.mSex = mSex; } }
當我們自動生成get set方法時,會將欄位的首字母大寫,我們在上面拼接set 方法時,也是基於這樣的規則來拼裝的。但是 當我們的欄位名為 aAbbb 時,則生成的get set 方法則不會大寫。解決方案也很簡單,注意欄位命名或者在拼接時對第二個自動進行大小寫判斷。這樣我們自己寫的Json解析工具就搞定, 以後每次解析只需一行程式碼即可OK。
今天反射就暫時講到這裡。其實反射的作用遠不於此,這裡只是使用了反射的冰山一角,結合註解和泛型,反射可以做的事更多,但是還是和開頭講的一樣,反射用起來雖然很爽,但是不能亂射,和頻繁的射,“射”的太多。“性”能會出問題!(o(∩_∩)o )。
相關文章
- Java高階特性之泛型學習總結Java泛型
- Java高階特性之列舉學習總結Java
- Java高階語法之反射Java反射
- Java高階特性之集合Java
- (小白學JAVA之)Java高階特性知識點梳理Java
- Java 高階特性之 instanceofJava
- Java學習之反射篇Java反射
- JAVA特性 之 反射(Reflection)Java反射
- 【java學習之容器總結】Java
- Java學習之LinkedHashMap學習總結JavaHashMap
- Java初階段學習的複習總結Java
- Go高階特性 15 | 執行時反射:字串和結構體之間轉換Go反射字串結構體
- JAVA基礎學習篇之反射Java反射
- oracle flashback特性學習總結Oracle
- C#反射機制學習總結C#反射
- 【Java 反射學習】Java 反射基礎Java反射
- [Java 反射學習] Java 反射基礎Java反射
- Java高階特性—泛型Java泛型
- Java資料結構之Map學習總結Java資料結構
- Java資料結構之Set學習總結Java資料結構
- Java學習:反射Java反射
- Java學習_反射Java反射
- Java反射學習Java反射
- 面試總結——Java高階工程師面試Java工程師
- Java學習總結Java
- JAVA高階程式設計之hibernate框架學習二Java程式設計框架
- Java之反射--練習Java反射
- Java高階特性增強-鎖Java
- 《Java 高階篇》八:新特性Java
- 最近Java高階工程師面試總結Java工程師面試
- 面試總結——Java高階工程師(二)面試Java工程師
- 面試總結——Java高階工程師(三)面試Java工程師
- 面試題總結 —— JAVA高階工程師面試題Java工程師
- java反射學習(一)Java反射
- java反射之動態代理學習筆記Java反射筆記
- Java集合學習總結Java
- Vue 近階段學習總結Vue
- JDK8新特性學習總結JDK