1. 程式人生 > >Java反射的使用--以一個簡單又典型例子講解

Java反射的使用--以一個簡單又典型例子講解

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~~~~";
@Override
protected 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