1 有了Class对象,能做什么?
- 创建类的对象:调用Class对象的newInstance() 方法
- 1)类必须有一个无参数的构造器
- 2)类的构造器的访问权限需要足够
思考? 难道没有无参的构造器就不能创建对象了吗?只要在操作时明确的调用类的构造器,并把参数传递进去之后,才可以实例化操作。
步骤如下:
- 1)通过Class类的getDeclaredConstructor(Class … parameterTypes) 取得本类的指定形参类型的构造器
- 2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数
- 3)通过Constructor实例化对象
2 调用指定的方法
通过反射,调用类中的方法,通过Method类完成。
① 通过Class类的getMethod(String name, Class…parameterTypes) 方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
② 之后使用Object invoke(Object obj,Object[] args) 进行调用,并向方法中传递要设置的obj对象的参数信息。
3 调用指定的方法
Object invoke(Object obj,Object … args)
- Object对应原方法的返回值,若原方法无返回值,此时返回null
- 若原方法为静态方法,此时形参Object obj可为null
- 若原方法形参列表为空,则Object[] args为null
- 若原方法声明为private,则需要在调用此invoke()方法前,显示调用方法对象的setAccessible(true)方法,将可访问private的方法。
4 setAccessible
- Method和Field、Constructor对象都要setAccessible()方法
- setAccessible作用是启动和禁用访问安全检查的开关
- 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查
- 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
- 使得原本无法访问的私有成员也可以访问
- 参数值为false则指示反射的对象应该实施Java语言访问检查
4.1 提高反射效率的代码演示
package com.annotation;
import com.annotation.bean.User;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test9 {
public static void test01(){
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法执行10亿次所需时间:"+(endTime-startTime)+"ms");
}
public static void test02() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class c1 = Class.forName("com.annotation.bean.User");
User user = (User) c1.newInstance();
//User user = new User();
Method getName = c1.getDeclaredMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方法执行10亿次所需时间:"+(endTime-startTime)+"ms");
}
public static void test03() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class c1 = Class.forName("com.annotation.bean.User");
User user = (User) c1.newInstance();
Method getName = c1.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭检测执行10亿次所需时间:"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
test01();
test02();
test03();
}
/* 运行结果:
普通方法执行10亿次所需时间:7ms
反射方法执行10亿次所需时间:4251ms
关闭检测执行10亿次所需时间:2423ms
*/
}
5 代码演示
(1)创建实体类 User
package com.annotation.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
}
(2)测试
package com.annotation;
import com.annotation.bean.User;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test8 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 获得Class对象
Class c1 = Class.forName("com.annotation.bean.User");
// 构造一个对象
User user = (User)c1.newInstance(); // 本质是调用了无参构造
System.out.println(user);
/* 结果:User(id=0, name=null) */
// 通过构造器创建对象
System.out.println("----");
Constructor constructor = c1.getDeclaredConstructor(int.class,String.class);
User user2 = (User) constructor.newInstance(1,"张三");
System.out.println(user2);
/* 结果:User(id=1, name=张三) */
// 调用普通方法
System.out.println("----");
user.setName("张三");
System.out.println(user.getName());
/* 结果:张三 */
// 通过反射获取一个方法,然后调用普通方法
System.out.println("----");
Method setName = c1.getDeclaredMethod("setName",String.class);
setName.invoke(user,"狂神"); // invoke:激活的意思
System.out.println(user.getName());
/* 结果:狂神 */
// 通过反射操作属性
System.out.println("----");
Field name = c1.getDeclaredField("name");
// 不能直接操作私有属性,我们需要关闭程序的安全检测
name.setAccessible(true);
name.set(user,"狂神2");
System.out.println(user.getName());
/* 结果:狂神2 */
}
}