Java反射的使用--以一個簡單又典型例子講解
阿新 • • 發佈:2018-12-23
Java反射是用來獲取Java中任意一個類中的所有方法和屬性。
一、Java反射的典型例子
1.新建一個Student類
public class Student { private static final String TAG = "~~~~Student~~~~"; private String studentName; private int studentAge; private Student(String studentName){ this.studentName = studentName; } private String show(String message){ Log.d(TAG, "show: " + studentName + "," + studentAge + ","+ message); return "abc"; } }
裡面有兩個欄位,一個帶引數的構造方法,一個帶引數和返回值的函式,且都是私有的。
2.MainActivity完整程式碼:
public class MainActivity extends AppCompatActivity { private static final String TAG = "~~~~MainActivity~~~~"; @Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); try { //1.通過字串獲取Class物件,這個字串必須帶上完整路徑名 Class studentClass = Class.forName("com.sample.testreflex.Student"); //2.獲取宣告的構造方法,傳入所需引數的類名,如果有多個引數,用','連線即可Constructor studentConstructor = studentClass.getDeclaredConstructor(String.class); //如果是私有的構造方法,需要呼叫下面這一行程式碼使其可使用,公有的構造方法則不需要下面這一行程式碼 studentConstructor.setAccessible(true); //使用構造方法的newInstance方法建立物件,傳入構造方法所需引數,如果有多個引數,用','連線即可 Object student = studentConstructor.newInstance("NameA"); //3.獲取宣告的欄位,傳入欄位名 Field studentAgeField = studentClass.getDeclaredField("studentAge"); //如果是私有的欄位,需要呼叫下面這一行程式碼使其可使用,公有的欄位則不需要下面這一行程式碼 studentAgeField.setAccessible(true); //使用欄位的set方法設定欄位值,傳入此物件以及引數值 studentAgeField.set(student,10); //4.獲取宣告的函式,傳入所需引數的類名,如果有多個引數,用','連線即可 Method studentShowMethod = studentClass.getDeclaredMethod("show",String.class); //如果是私有的函式,需要呼叫下面這一行程式碼使其可使用,公有的函式則不需要下面這一行程式碼 studentShowMethod.setAccessible(true); //使用函式的invoke方法呼叫此函式,傳入此物件以及函式所需引數,如果有多個引數,用','連線即可。函式會返回一個Object物件,使用強制型別轉換轉成實際型別即可 Object result = studentShowMethod.invoke(student,"message"); Log.d(TAG, "result: " + (String) result); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } }
3.執行程式,Log 控制檯輸出如下:
/com.sample.testreflex D/~~~~Student~~~~: show: NameA,10,message /com.sample.testreflex D/~~~~MainActivity~~~~: result: abc
以上就是Java反射機制的典型例子。
二、拓展
1.為了方便演示,在Student中新增公有的無參構造方法:
public Student(){ }
獲取Class物件的三種方式:
//1.1通過字串獲取Class物件,這個字串必須帶上完整路徑名 Class studentClass = Class.forName("com.sample.testreflex.Student"); //1.2通過類的class屬性 Class studentClass2 = Student.class; //1.3通過物件的getClass()函式 Student studentObject = new Student(); Class studentClass3 = studentObject.getClass();
第一種就是上面典型例子中的方法,通過字串獲取Class物件,這也是最常用的反射獲取Class物件的方法;
第二種有限制條件:需要匯入類的包;
第三種已經有了物件,不再需要反射。
通過這三種方式獲取到的Class物件是同一個,也就是說Java執行時,每一個類只會生成一個Class物件。
2.獲取類中所有的構造方法
//2.1獲取所有宣告的構造方法 Constructor[] declaredConstructorList = studentClass.getDeclaredConstructors(); for(Constructor declaredConstructor:declaredConstructorList){ Log.d(TAG, "declared Constructor: " + declaredConstructor); } //2.2獲取所有公有的構造方法 Constructor[] constructorList = studentClass.getConstructors(); for(Constructor constructor:constructorList){ Log.d(TAG, "constructor: " + constructor); }執行程式,Log控制檯輸出如下:
/com.sample.testreflex D/~~~~MainActivity~~~~: declared Constructor: public com.sample.testreflex.Student() declared Constructor: private com.sample.testreflex.Student(java.lang.String) declared Constructor: com.sample.testreflex.Student(java.lang.Object[],com.android.tools.ir.runtime.InstantReloadException) constructor: public com.sample.testreflex.Student()
3.獲取類中所有的欄位
//3.1獲取所有宣告的欄位 Field[] declaredFieldList = studentClass.getDeclaredFields(); for(Field declaredField:declaredFieldList){ Log.d(TAG, "declared Field: " + declaredField); } //3.2獲取所有公有的欄位 Field[] fieldList = studentClass.getFields(); for(Field field:fieldList){ Log.d(TAG, "field: " + field); }
執行程式,Log控制檯輸出如下:
D/~~~~MainActivity~~~~: declared Field: private int com.sample.testreflex.Student.studentAge declared Field: private java.lang.String com.sample.testreflex.Student.studentName declared Field: public static transient volatile com.android.tools.ir.runtime.IncrementalChange com.sample.testreflex.Student.$change declared Field: private static final java.lang.String com.sample.testreflex.Student.TAG declared Field: public static final long com.sample.testreflex.Student.serialVersionUID field: public static transient volatile com.android.tools.ir.runtime.IncrementalChange com.sample.testreflex.Student.$change field: public static final long com.sample.testreflex.Student.serialVersionUID
4.獲取類中所有的函式
//4.1獲取所有宣告的函式 Method[] declaredMethodList = studentClass.getDeclaredMethods(); for(Method declaredMethod:declaredMethodList){ Log.d(TAG, "declared Method: " + declaredMethod); } //4.2獲取所有公有的函式 Method[] methodList = studentClass.getMethods(); for(Method method:methodList){ Log.d(TAG, "method: " + method); }
執行程式,Log控制檯輸出如下:
/com.sample.testreflex D/~~~~MainActivity~~~~: declared Method: public static java.lang.Object com.sample.testreflex.Student.access$super(com.sample.testreflex.Student,java.lang.String,java.lang.Object[]) declared Method: private java.lang.String com.sample.testreflex.Student.show(java.lang.String) method: public static java.lang.Object com.sample.testreflex.Student.access$super(com.sample.testreflex.Student,java.lang.String,java.lang.Object[]) method: public boolean java.lang.Object.equals(java.lang.Object) method: public final java.lang.Class java.lang.Object.getClass() method: public int java.lang.Object.hashCode() method: public final native void java.lang.Object.notify() method: public final native void java.lang.Object.notifyAll() method: public java.lang.String java.lang.Object.toString() method: public final native void java.lang.Object.wait() throws java.lang.InterruptedException method: public final void java.lang.Object.wait(long) throws java.lang.InterruptedException method: public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException