文章目录
Java反射
1、什么是反射?
①java代码在计算机中运行的阶段
java源码——>通过编译——>Class类对象——>通过创建对象——>Runtime阶段。
注意!
在源代码阶段创建对象直接通过new可以完成,但是在Runtime阶段需要操作一些字段或者是方法就需要通过反射机制来进行。
②反射机制
Java反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有字段和方法;对于任意一个对象都能够调用它的任意字段和方法这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。
③反射的优点
可以在程序运行的过程中操作对象和字节码文件,不需要重新编译。
提高程序的扩展性、复用性、解耦。
2、反射能做什么?
-
获取Class类对象
-
获取Filed字段
-
获取method方法
-
获取constructor构造器
3、反射常用的方法
在说常用方法之前,先知道获取到类对象的三种方式,因为无论是获取Filed、method、constructor都是通过类对象来进行的。
@Test
public void testGetClass() throws ClassNotFoundException {
/*
在程序运行的过程当中,找到类对象的三种方式。
1、通过:类名.class
2、通过:对象名.getClass()
3、通过:Class.forName("全路径类名");
*/
//1
Class<User> userClass = User.class;
//2
User user = new User();
Class<? extends User> userClass2 = user.getClass();
//3
Class<?> userClass3 = Class.forName("com.demo.reflection.User");
}
①Class类对象常用方法
方法名 | 方法功能描述 |
---|---|
getPackage() | 获取包名 |
getName() | 获取全路径类名 |
getSimpleName() | 获取类名 |
getMethod(“方法名”) | 获取对象指定的方法 |
getDeclaredMethod(“方法名”) | 不限制访问类型获取对象指定的方法 |
getMethods() | 获取对象的所有方法 |
getDeclaredMethods() | 不限定访问修饰符获取所有方法 |
getField(“字段名”) | 获取字段 |
getDeclaredField(“字段名”) | 不限定访问修饰符获取字段 |
getFields() | 获取对象的所有字段 |
getDeclaredFields() | 不限定访问修饰符获取对象的字段 |
getConstructor(String.class) | 通过指定的参数类型获取构造器 |
getDeclaredConstructor(String.class) | 不限定访问修饰符获取构造器 |
getConstructors() | 获取所有的构造器 |
getDeclaredConstructors() | 不限定访问修饰符获取所有构造器 |
newInstance() | 创建对象,使用默认构造器创建 |
… | … |
②Filed对象常用方法(通过Class对象获取Filed对象后)
方法名 | 方法功能描述 |
---|---|
setAccessible(true) | 对字段进行暴力反射 |
getName() | 获取字段名称 |
getType() | 获取字段类型 |
getAnnotation(LoginAnnotation.class) | 获取字段上指定的注解 |
getDeclaredAnnotation(LoginAnnotation.class) | 不分注解的访问修饰符,获取字段上指定的注解 |
getAnnotations() | 获取字段上所有的注解 |
getDeclaredAnnotations() | 不分注解的访问修饰符,获取字段上所有的注解 |
set(对象, “yyy”) | 设置指定对象的字段值 |
get(对象) | 获取指定对象的字段值 |
… | … |
③Method对象常用方法(通过Class对象获取Method对象后)
方法名 | 方法功能描述 |
---|---|
setAccessible(true) | 暴力反射该方法 |
getAnnotation(LoginAnnotation.class) | 获取方法上指定的注解 |
getDeclaredAnnotation(LoginAnnotation.class) | 不分注解的访问修饰符,获取方法上指定的注解 |
getName() | 获取方法名 |
invoke(user, “执行该方法的参数”) | 执行该方法 |
getReturnType() | 获取方法的返回值类型 |
getParameterCount() | 获取该方法形参表参数个数 |
getParameterTypes() | 获取形参表参数类型,返回Class对象数组类型 |
… | … |
④Constructor对象常用方法(通过Class对象获取Constructor对象后)
方法名 | 方法功能描述 |
---|---|
setAccessible(true) | 暴力反射该构造器 |
getAnnotation(LoginAnnotation.class) | 获取字段上指定的注解 |
getDeclaredAnnotation(LoginAnnotation.class) | 不分注解的访问修饰符,获取字段上指定的注解 |
getName() | 获取构造器名 |
getParameterCount() | 获取该方法形参表参数个数 |
getParameterTypes() | 获取形参表参数类型,返回Class对象数组类型 |
constructor.newInstance(“构造参数列表”) | 创建对象 |
… | … |
4、反射案例
功能:执行sayHello方法,在执行这个方法前后分别输出一句话。
public class User {
public String sayHello(String speak) {
System.out.println(speak);
return speak;
}
public String sayHello(String speak, Integer speakNum) {
System.out.println("这是我第 " + speakNum + " 次说:" + speak);
return speak;
}
}
public class ReflectTest {
public static Object testInvokeMethod(Class<?> aClass, String method, Object... args) throws Exception {
Class<?>[] paramType = new Class[args.length];
//获取,参数的参数类型
for (int i = 0; i < args.length; i++) {
paramType[i] = args[i].getClass();
}
//通过方法名获取方法
Method sayHello = aClass.getMethod(method, paramType);
if (sayHello != null) {
System.out.println("执行方法前输出...");
//执行方法
sayHello.setAccessible(true);
Object invoke = sayHello.invoke(aClass.newInstance(), args);
System.out.println("执行方法后输出...");
return invoke;
}
return null;
}
public static void main(String[] args) throws Exception {
testInvokeMethod(User.class, "sayHello", "你好吗?"); //一个参数的sayHello
System.out.println("*******************");
testInvokeMethod(User.class, "sayHello", "你好吗?", 3); //sayHello重载方法,两个参数
}
}
"); //一个参数的sayHello
System.out.println("*******************");
testInvokeMethod(User.class, "sayHello", "你好吗?", 3); //sayHello重载方法,两个参数
}
}