转:
你知道的反射是这样吗?(二)
在上一篇文章,已经讲到了反射的一些基本概念以及基本的使用,也介绍到了一些反射中常用的方法以及区别,今天我们再次进入反射的第二期,更进一步的了解一下反射。
我们在使用反射去创建一个类的实例的时候一般都是使用:
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知识。如果你有兴趣,可以关注我后续将带来更多精彩的文章。
转: