反射
1.将Java文件保存到本地硬盘
2.编译Java文件,生成.class文件
3.使用Java虚拟机(JVM)将字节码文件加载到内存
4.字节码文件在内存中使用Class类表示
5.使用反射的时候,首先获取到Class类,就可以得到class文件里的所有内容,包含属性、构造方法、普通方法
6.属性通过Filed类表示
7.构造方法通过Constructor表示
8.普通方法通过Method表示
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
万物皆对象,类也是对象;任何一个类都是Class类的一个实例对象,这个对象我们成为该类的类类型
反射的执行效率低,把setassceible设为true可以提高效率
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Apple {
private String color;
}
得到Class类对象的3种方式
//1
Class clz = Class.forName("cn.zy.pojo.Apple");
//2
Class clz = Apple.class;
//3
Apple apple=new Apple();
Class clz = apple.getClass();//这种方法必须先实例化
通过反射创建对象
Constructor constructor = c.getConstructor(String.class);//有参参构造器
Constructor constructor2 = c.getConstructor();//无参构造器
//初始化
Apple apple1 = (Apple)constructor.newInstance("red"); //有参构造器
Apple apple2 = (Apple)constructor2.newInstance(); //无参构造器
另一种方法
Class clz = Apple.class;
Apple apple = (Apple)clz.newInstance(); //底层调用Class类的newInstance()方法获取构造器
获取构造器
Constructor constructor = c.getConstructor(String.class);//有参参构造器
Constructor constructor2 = c.getConstructor();//无参构造器
//获取私有构造器
Constructor constructor2 = c1.getDeclaredConstructor(String.class);
constructor2.setAccessible(true);//强制清除了java的权限检测,设置可以访问
获取成员变量
成员变量分 public 和 private
获取public成员变量需要 只需要 通过getField(String 属性名)获取;
获取private成员变量需要 通过getDeclaredField(String 属性名)获取,并且 需要必须使用field.setAccessible(true)跳过权限检查;
Class clz = Apple.class;
/*Constructor constructor = clz.getConstructor();
Apple apple = (Apple)constructor.newInstance();*/
Apple apple = new Apple();
/*
获取 public 成员变量,不需要setAccessible(true)
Field field = clz.getField("color");
*/
//获取私有成员变量getDeclaredField(String 属性名)
Field field = clz.getDeclaredField("color");
field.setAccessible(true); //获取私有成员变量时,必须使用setAccessible(true)跳过权限检查
field.set(apple,"red");
System.out.println(apple.toString());
获取成员方法
Class clz = Apple.class;
//得到非私有成员函数并调用这个方法
Method method= c1.getMethod("setColor",String.class); //1 方法名,2 方法参数
Apple apple=new Apple();//通过反射得到的对像与new出来的没有区别
//调用方法
method.invoke(apple,"green");
System.out.println(apple.toString());
得到类加载器
Class c = Apple.class;
Object o = c.getClassLoader();
得到这个类实现的所有接口
Class[] interfaces = c1.getInterfaces();
System.out.println(interfaces);
得到配置文件
/*
配置文件的路径(相对路径也可以)
*/
obj = c1.getResource("/log4j.properties");
System.out.println(obj);
通过反射调用复杂的方法
@RunWith(SpringRunner.class)
@SpringBootTest
public class MPTest {
@Resource
HskstgcpjService hskstgcpjService;
@Test
public void t1() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//不能传入QueryWrapper.class,不能传入子类 必须 保持一致
Method method = IraqpjxmServiceImpl.class.getMethod("list", Wrapper.class);
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.select("id");
Object o = method.invoke(hskstgcpjService,queryWrapper);
}
}
invoke(对象,参数对象)
注意,getMethod(方法名,参数类型);参数类型必须一致,即使传入子类也不行;