你知道的反射是这样吗?(二)

在上一篇文章,已经讲到了反射的一些基本概念以及基本的使用,也介绍到了一些反射中常用的方法以及区别,今天我们再次进入反射的第二期,更进一步的了解一下反射。
我们在使用反射去创建一个类的实例的时候一般都是使用:

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知识。如果你有兴趣,可以关注我后续将带来更多精彩的文章。

posted @ 2020-09-14 10:52  Mr.栋  阅读(501)  评论(0编辑  收藏  举报