在上一篇文章,已經講到了反射的一些基本概念以及基本的使用,也介紹到了一些反射中常用的方法以及區別,今天我們再次進入反射的第二期,更進一步的瞭解一下反射。
我們在使用反射去建立一個類的例項的時候一般都是使用:
Class clazz = Test.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Object obj = constructor.newInstance();
這種寫法稍顯繁雜,我們可以通過另一種便捷的方式去實現:
Class clazz = Test.class;
Test instance1 = clazz.newInstance();
這種方式雖然不直接使用構造器物件,但是這種方式是有缺陷的:
1、如果需要例項化的Test類無參構造方法使用private修飾則會出現java.lang.IllegalAccessException異常,因為沒有許可權訪問。
2、如果我們沒有無參構造方法,因為newInstance()是不需要傳參的,在執行時newInstance()只會尋找公共的、無參的構造方法。
注意:在這裡我們一定要區分newInstance這個方法,這裡的newInstance方法是Class下的一個方法,與Constructor中的newInstance方法是不一樣的。
Method物件的使用
如果我們需要獲取某一個類中的所有Method物件,我們還是需要通過位元組碼物件去操作。比如我們現在需要和獲取到Test2類中的所有Method物件。
public class Test2 {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Test2{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private void test(){
System.out.println("I'm test method");
}
}
我們在Test2中提供了get、set方法,也重寫了toString方法,並且也建立了一個私有的test方法,然後再通過使用getDeclaredMethods()方法獲取到了Test2中所有的Method物件。
Class clazz = Test2.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
但是如果使用getMethods()這個時候我們就不能獲取到私有Method物件了,如果我們需要獲取指定的方法則可以使用getMethod(name)或者getDeclaredMethod(name),至於他們兩個的區別就不再贅述。
那麼又有一個問題出現了,Java是有多型特性的,如果我們有某一個方法進行了方法過載,那麼這個時候我們如果根據方法名稱去獲取不就有問題了嗎?不用急,我們可以通過getMethod(name,paramClassType)或者getDeclaredMethod(name,paramClassType)獲取到我們指定的過載方法。如:
public class Test{
private void test(){
System.out.println("I'm test method");
}
private void test(String name, Integer age){
System.out.println("I'm test method:"+name+age+"歲");
}
}
// 通過此方式便可以獲取到我們指定的過載方法
Method test = clazz.getDeclaredMethod("test", String.class, Integer.class);
獲取到指定的方法後我們要如何使用?
我們一般在使用一個方法的時候都是obj.method(param);但是如果我們需要用反射進行呼叫則需要,method.invoke(obj,param);
Class clazz = Test2.class;
Method test = clazz.getDeclaredMethod("test", String.class, Integer.class);
test.setAccessible(true);
test.invoke(clazz.newInstance(), "zhangsan", 12);
Field物件如何使用呢?
這裡其實與Class、Method物件都是大同小異了,都是同樣的玩法。
Class clazz = Test2.class;
Field field1 = clazz.getDeclaredField("name");
Field field2 = clazz.getDeclaredField("age");
Test2 test2 = clazz.newInstance();
field1.setAccessible(true);
field1.set(test2, "張三");
field2.setAccessible(true);
field2.set(test2, 12);
System.out.println(test2);
至此我們的反射也就已經整體結束了,後續將繼續努力給大家帶來一些易懂的Java知識。如果你有興趣,可以關注我後續將帶來更多精彩的文章。