java动态代理 反射调用方法对象
正常java获得一个对象是通过反射 现在我们用Class来获得对象
创建类的对象:调用class对象的newInstance()方法
并且类必须有一个无参构造器
//动态对象,通过反射
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//获得class对象
Class c1 = Class.forName("Dome3.Person");
//构造一个对象
Person person = (Person) c1.newInstance();//调用的是无参构造器
System.out.println(person);
}
}
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Person{name=‘null’} 输出结果可以看到调用的是无参构造器,如果想调用有参构造器怎么办呢?
可以通过Class类的getDeclaredConstructor()取得本类指定的形参类型的构造器
向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。通过Constructor实例化对象
//动态对象,通过反射
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//获得class对象
Class c1 = Class.forName("Dome3.Person");
//构造一个对象
// Person person = (Person) c1.newInstance();//调用的是无参构造器
// System.out.println(person);
//通过构造器来创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class);
Person person1 = (Person) constructor.newInstance("li", 20);
System.out.println(person1);
}
}
可以看到通过构造器可以调用对象的有参构造器
通过反射来调用普通方法
通过反射,调用类中的方法,通过Method类完成。
通过Class类的getDeclaredMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
//通过反射调用普通方法
Person c3 = (Person) c1.newInstance();
//通过反射获取一个方法
Method name = c1.getDeclaredMethod("setName", String.class);
//invoke(对象,方法的值)
name.invoke(c3,"无敌的我又回来了");
System.out.println(c3.getName());
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8eRNOHmF-1659068260546)(C:\Users\Lizhenhai\AppData\Roaming\Typora\typora-user-images\image-20220729113855933.png)]
通过反射来操作属性
//通过反射操作属性
Person c4 = (Person) c1.newInstance();
Field name1 = c1.getDeclaredField("name");
name1.setAccessible(true);//因为name属性私有,所以需要赋予操作权限,就可以操作私有属性
name1.set(c4, "无敌");
System.out.println(c4.getName());
setAccessible
Method和Field、Constructor对象都有setAccessible()方法。setAccessible作用是启动和禁用访问安全检查的开关。
参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。使得原本无法访问的私有成员也可以访问
参数值为false则指示反射的对象应该实施Java语言访问检查
下面来做一下性能对比分析
public class Test03 {
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
test1();
test2();
test3();
}
//反射方式调用
public static void test1() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Person person = new Person();
Class c1 = person.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
//设置时间点
long startTime = System.currentTimeMillis();//获取开始时间
for (int i = 0; i < 100000000; i++) {
getName.invoke(person,null);
}
long endTime = System.currentTimeMillis();//获取结束时间
System.out.println("反射调用方法执行1亿次"+(endTime-startTime)+"ms");
}
//反射方式调用 关闭检测
public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Person person = new Person();
Class c1 = person.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
getName.setAccessible(true);
//设置时间点
long startTime = System.currentTimeMillis();//获取开始时间
for (int i = 0; i < 100000000; i++) {
getName.invoke(person,null);
}
long endTime = System.currentTimeMillis();//获取结束时间
System.out.println("反射调用方法关闭检测执行1亿次"+(endTime-startTime)+"ms");
}
//普通方法调用
public static void test3(){
Person person = new Person();
//设置时间点
long startTime = System.currentTimeMillis();//获取开始时间
for (int i = 0; i < 100000000; i++) {
person.getName();
}
long endTime = System.currentTimeMillis();//获取结束时间
System.out.println("普通调用方法执行1亿次"+(endTime-startTime)+"ms");
}
}
可以看到普通调用方法是最节约资源的
如果平时反射调用多可以建议关闭检测提升效率