編輯:關於Android編程
反射是一種能夠在程序運行時動態訪問、修改某個類中任意屬性(狀態)和方法(行為)的機制(包括private實例和方法),java反射機制提供了以下幾個功能:
在運行時判斷任意一個對象所屬的類;
在運行時構造任意一個類的對象;
在運行時判斷任意一個類所具有的成員變量和方法;
在運行時調用任意一個對象的方法。
反射涉及到四個核心類:
java.lang.Class.java:類對象;
java.lang.reflect.Constructor.java:類的構造器對象;
java.lang.reflect.Method.java:類的方法對象;
java.lang.reflect.Field.java:類的屬性對象;
操作因訪問權限限制的屬性和方法;
實現自定義注解;
動態加載第三方jar包,解決android開發中方法數不能超過65536個的問題;
按需加載類,節省編譯和初始化APK的時間;
當我們編寫完一個Java項目之後,每個java文件都會被編譯成一個.class文件,這些Class對象承載了這個類的所有信息,包括父類、接口、構造函數、方法、屬性等,這些class文件在程序運行時會被ClassLoader加載到虛擬機中。當一個類被加載以後,Java虛擬機就會在內存中自動產生一個Class對象。我們通過new的形式創建對象實際上就是通過這些Class來創建,只是這個過程對於我們是不透明的而已。
反射的工作原理就是借助Class.java、Constructor.java、Method.java、Field.java這四個類在程序運行時動態訪問和修改任何類的行為和狀態。
父類Personon.java:
package com.eebbk.reflectdemo; public class Person { String mName; String mSex; public int mAge; public Person(String aName, String aSex, int aAge) { mName = aName; mSex = aSex; mAge = aAge; } public int getmAge() { return mAge; } public void setmAge(int mAge) { this.mAge = mAge; } public String getmName() { return mName; } public void setmName(String mName) { this.mName = mName; } public String getmSex() { return mSex; } public void setmSex(String mSex) { this.mSex = mSex; } private String getDescription() { return "黃種人"; } }
接口ICompany.java:
package com.eebbk.reflectdemo; public interface ICompany{ String getCompany(); }
子類ProgramMonkey.java:
package com.eebbk.reflectdemo; public class ProgramMonkey extends Person implements ICompany { String mLanguage = "C#"; String mCompany = "BBK"; public ProgramMonkey(String aName, String aSex, int aAge) { super(aName, aSex, aAge); } public ProgramMonkey(String language, String company, String aName, String aSex, int aAge) { super(aName, aSex, aAge); mLanguage = language; mCompany = company; } public String getmLanguage() { return mLanguage; } public void setmLanguage(String mLanguage) { this.mLanguage = mLanguage; } private int getSalaryPerMonth() { return 12306; } @Override public String getCompany() { return mCompany; } }
public class ReflectActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_reflect_layout); } public void onClick(View v) { switch (v.getId()) { case R.id.getClassObjectBtnId: { getClassObject(); } break; case R.id.getMethodInfoBtnId: { getMethodInfo(); } break; case R.id.getFieldInfoBtnId: { getFieldInfo(); } break; case R.id.getSuperClassInfoBtnId: { getSuperClass(); } break; case R.id.getInterfaceInfoBtnId: { getInterfaces(); } break; case R.id.compareMethodAndFieldBtnId: { compareCallMethodAndField(); } break; default: { } break; } } private void getClassObject() { Class classObject = null; classObject = getClassObject_1(); LogE("classObject_1 name : " + classObject.getName()); classObject = getClassObject_2(); LogE("classObject_2 name : " + classObject.getName()); classObject = getClassObject_3(); LogE("classObject_3 name : " + classObject.getName()); } private void getMethodInfo() { getAllMethods(); getCurrentClassMethods(); } private void getFieldInfo() { getAllFields(); getCurrentClassFields(); } private void getSuperClass() { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); Class superClass = programMonkey.getClass().getSuperclass(); while (superClass != null) { Log.e("programMonkey's super class is : " + superClass.getName()); // 再獲取父類的上一層父類,直到最後的 Object 類,Object 的父類為 null superClass = superClass.getSuperclass(); } } private void getInterfaces() { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); Class[] interfaceses = programMonkey.getClass().getInterfaces(); for (Class class1 : interfaceses) { Log.e("programMonkey's interface is : " + class1.getName()); } } private void compareCallMethodAndField() { long callMethodCostTime = getCallMethodCostTime(10000); Log.e("callMethodCostTime == " + callMethodCostTime); long callFieldCostTime = getCallFieldCostTime(10000); Log.e("callFieldCostTime == " + callFieldCostTime); } private long getCallMethodCostTime(int count) { long startTime = System.currentTimeMillis(); for (int index = 0; index < count; index++) { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); try { Method setmLanguageMethod = programMonkey.getClass().getMethod( "setmLanguage", String.class); setmLanguageMethod.setAccessible(true); setmLanguageMethod.invoke(programMonkey, "Java"); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } return System.currentTimeMillis() - startTime; } private long getCallFieldCostTime(int count) { long startTime = System.currentTimeMillis(); for (int index = 0; index < count; index++) { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); try { Field ageField = programMonkey.getClass().getDeclaredField( "mLanguage"); ageField.set(programMonkey, "Java"); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return System.currentTimeMillis() - startTime; } /** * 獲取當前類中的所有方法 * * */ private void getCurrentClassMethods() { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); Method[] methods = programMonkey.getClass().getDeclaredMethods(); for (Method method : methods) { LogE("declared method name : " + method.getName()); } try { Method getSalaryPerMonthMethod = programMonkey.getClass().getDeclaredMethod("getSalaryPerMonth"); getSalaryPerMonthMethod.setAccessible(true); // 獲取返回類型 Class returnType = getSalaryPerMonthMethod.getReturnType(); Log.e("getSalaryPerMonth 方法的返回類型 : " + returnType.getName()); // 獲取方法的參數類型列表 Class[] paramClasses = getSalaryPerMonthMethod.getParameterTypes(); for (Class class1 : paramClasses) { Log.e("getSalaryPerMonth 方法的參數類型 : " + class1.getName()); } // 是否是 private 函數,屬性是否是 private 也可以使用這種方式判斷 LogE(getSalaryPerMonthMethod.getName()+ " is private "+ Modifier.isPrivate(getSalaryPerMonthMethod.getModifiers())); // 執行方法 Object result = getSalaryPerMonthMethod.invoke(programMonkey); LogE("getSalaryPerMonth 方法的返回結果: " + result); } catch (Exception e) { e.printStackTrace(); } } /** * 獲取當前類和父類的所有公有方法 * * */ private void getAllMethods() { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); // 獲取當前類和父類的所有公有方法 Method[] methods = programMonkey.getClass().getMethods(); for (Method method : methods) { Log.e("method name : " + method.getName()); } try { Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class); setmLanguageMethod.setAccessible(true); // 獲取返回類型 Class returnType = setmLanguageMethod.getReturnType(); Log.e("setmLanguage 方法的返回類型 : " + returnType.getName()); // 獲取方法的參數類型列表 Class[] paramClasses = setmLanguageMethod.getParameterTypes(); for (Class class1 : paramClasses) { Log.e("setmLanguage 方法的參數類型 : " + class1.getName()); } // 是否是 private 函數,屬性是否是 private 也可以使用這種方式判斷 Log.e(setmLanguageMethod.getName() + " is private "+ Modifier.isPrivate(setmLanguageMethod.getModifiers())); // 執行方法 Object result = setmLanguageMethod.invoke(programMonkey, "Java"); Log.e("setmLanguage 方法的返回結果: " + result); } catch (Exception e) { e.printStackTrace(); } } private Class getClassObject_1() { return ProgramMonkey.class; } private Class getClassObject_2() { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); return programMonkey.getClass(); } private Class getClassObject_3() { try { return Class.forName("com.eebbk.reflectdemo.ProgramMonkey"); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } /** * 得到當前類的所有實例 * * */ private void getCurrentClassFields() { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); // 獲取當前類的所有屬性 Field[] publicFields = programMonkey.getClass().getDeclaredFields(); for (Field field : publicFields) { Log.e("declared field name : " + field.getName()); } try { // 獲取當前類的某個屬性 Field ageField = programMonkey.getClass().getDeclaredField("mAge"); // 獲取屬性值 Log.e(" my age is : " + ageField.getInt(programMonkey)); // 設置屬性值 ageField.set(programMonkey, 10); LogE(" my age is : " + ageField.getInt(programMonkey)); } catch (Exception e) { e.printStackTrace(); } } } /** * 得到當前類和父類的所有公有屬性 * * */ private void getAllFields() { ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12); // 得到當前類和父類的所有公有屬性 Field[] publicFields = programMonkey.getClass().getFields(); for (Field field : publicFields) {
try {Log.e("field name : " + field.getName()); // 獲取當前類和父類的某個公有屬性Field ageField = programMonkey.getClass().getField("mAge"); LogE(" age is : " + ageField.getInt(programMonkey)); ageField.set(programMonkey, 8); LogE(" my age is : " + ageField.getInt(programMonkey));
三種獲取類信息的方式:
獲取當前類的方法、獲取當前類和父類的所有公有方法:
獲取當前類的所有實例、獲取當前類和父類的所有公有實例:
獲取父類信息:
獲取接口信息:
比較反射方法和實例的性能差異:
通過上面的示例可以發現,通過反射能夠完成之前所描述的事情,並且反射方法比反射實例要慢很多。
性能問題:通過反射訪問、修改類的屬性和方法時會遠慢於直接操作,但性能問題的嚴重程度取決於在程序中是如何使用反射的。如果使用得很少,不是很頻繁,性能將不會是什麼問題;
安全性問題:反射可以隨意訪問和修改類的所有狀態和行為,破壞了類的封裝性,如果不熟悉被反射類的實現原理,隨意修改可能導致潛在的邏輯問題;
兼容性問題:因為反射會涉及到直接訪問類的方法名和實例名,不同版本的API如果有變動,反射時找不到對應的屬性和方法時會報異常;
通過反射訪問方法比實例慢很多;
有用到反射的類不能被混淆;
反射存在性能問題,但使用不頻繁、按需使用時,對程序性能影響並不大;
反射存在安全性問題,因為可以隨意修改類的所有狀態和行為(包括private方法和實例);
使用反射訪問Android的API時需要注意因為不同API版本導致的兼容性問題;
Canvascanvas是一種抽象概念,是2D圖形系統中的重要部分,canvas一系列函數最終都是android 2D圖形庫Skia的一些列封裝,對應在SKCanvas.
前言先看看效果怎麼樣不錯吧?別急下面我就一步一步的教你實現。用到的知識點總結:1.Canvas和pint的使用,我們用它畫點,線,字2.View的基本用法其實做這個東西還
前言:因為找了N多網上的資源都沒有好的解決方案,別人都是只給思路沒給具體源碼,真TMD糾結,干嘛求別人,自己動手才是真,最痛恨那些所謂大牛的作風,給了點點代碼就讓別人去想
有時候用Eclipse想按住ctrl鍵查看源碼怎麼辦? 下面具體步驟讓你輕松看源碼: 點擊android.jar下面的source: 這裡可以添加zip和文件夾,zi