有一句话是这么说的:反射是框架设计的灵魂
使用反射的前提是必须先得到一个类的的Class对象,在 Java 中,有三种常见获取类的 Class 对象的方式:
- 使用.class语法:例如 String.class,这种方式适用于已知类的情况下,在编译时就能确定类的类型。
- 调用对象的.getClass()方法:例如 obj.getClass(),这种方式适用于已经有一个对象实例,想要获取其类的情况。
- 使用静态方法 Class.forName(“ClassName”):例如 Class.forName(“java.lang.String”),这种方式适用于只知道类的名称(字符串形式),而不知道具体的类。
反射的概述:
Java 的反射机制指的是在运行时检查、获取和修改类的属性、方法、构造方法等信息的能力。它允许程序在运行时动态获取类的信息并操作类的成员。
主要概念和用途:
- Class 类:在 Java 中,每个类都有一个对应的 Class 对象,这个对象包含了与类相关的元数据信息,比如类的名称、访问修饰符、父类、实现的接口等。
- 反射 API:Java 反射提供了一组类(如 Class、Method、Field、Constructor 等)来操作类的属性、方法、构造方法等。
- 动态加载类:通过反射可以在运行时动态加载一个类,而不需要在编译时就将其确定下来。
- 运行时创建对象:可以通过反射机制在运行时创建类的对象,即使在编译时无法确定具体的类。
- 操作类的成员:可以获取和操作类的字段(属性)、方法、构造方法等,甚至可以调用私有成员。
- 框架和工具的基础:反射是很多 Java 框架和工具的基础,例如 Spring 框架、ORM(对象关系映射)工具如 Hibernate,它们利用反射机制来实现自动化配置、依赖注入、动态代理等功能。
怎么使用反射机制
反射中重要的一些类:
类 | 含义 |
---|---|
java.lang.Class | 整个字节码对象,代表一整个类 |
java.lang.reflect.Method | 字节码中的方法字节码,代表类中的方法 |
java.lang.reflect.Constructor | 字节码中的构造方法字节码,代表类中的构造方法 |
java.lang.reflect.Field | 字节码中的属性字节码,代表类中的成员变量(静态变量 + 实例变量) |
其中:
Class 类
Class 代表类的实体,在运行的 java应用程序中表示类和接口。在这个类中提供了很多有用的方法:
1、获得类相关
asSubclass(Class<?> clazz) : 把传递的类的对象转换成代表其子类的对象
Cast : 把对象转换成代表类或是接口的对象
getClassLoader() : 获得类的加载器
getClasses() :返回一个数组,数组中包含该类中所有公共类和接口类的对象
getDeclaredClasses() :返回一个数组,数组中包含该类中所有类和接口类的对象
forName(String className) 根据类名返回类的对象
getName() : 获得类的完整路径名字
newInstance() :创建类的实例
getPackage() :获得类的包
getSimpleName() :获得类的名字
getSuperclass() : 获得当前类继承的父类的名字
getInterfaces() :获得当前类实现的类或是接口
2、获得类中属性
getField(String name) : 获得某个公有的属性对象
getFields() :获得所有公有的属性对象
getDeclaredField(String name):获得某个属性对象
getDeclareFields() :获得所有属性对象
3、获得类中构造器
getConstructor(Class… <?> parameterTypes) :获得该类中与参数类型匹配的公有构造方法 getConstructors() :获得该类的所有公有构造方法 getDeclaredConstructor(Class ...<?> parameterTypes):获得该类中与参数类型匹配的构造方法
getDeclaredConstructors() : 获得该类所有构造方法
4、获得类中方法
getMethod(String name,Class…<?> parameterTypes) : 获得该类某个公有的方法 getMethods() : 获得该类所有公有的方法 getDeclaredMethod(String name,Class...<?> parameterTypes) : 获得该类某个方法
getDeclaredMethods() : 获得该类所有方法
示例类:
package com.money.provider;
/**
* Author: money
* Description: TODO
* Date: 2024/6/16 11:58
* Version: 1.0
*/
public class User {
private String name;
private Integer age;
static {
System.out.println("静态代码块执行,在构造方法前完成");
}
public User() {
super();
System.out.println("无参构造执行");
}
public User(String name){
super();
System.out.println("名字单参数构造执行");
this.name = name;
}
public User(String name, Integer age) {
super();
System.out.println("满参构造执行");
this.name = name;
this.age = age;
}
private User(Integer age){
System.out.println("调用私有构造方法");
}
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;
}
public void hello(){
System.out.println("hello方法执行,我是" + name);
}
private Integer add(Integer a,Integer b){
return a + b;
}
}
获取Class 对象:
三种方式示例:
@Test
public void getClassTest() throws ClassNotFoundException {
// 方式1
Class<?> aClass = Class.forName("com.money.provider.User");
System.out.println(aClass);
// 方式2
com.money.provider.User user = new com.money.provider.User();
Class<? extends com.money.provider.User> aClass1 = user.getClass();
System.out.println(aClass1);
// 方式3
Class<com.money.provider.User> userClass = com.money.provider.User.class;
System.out.println(userClass);
}
反射实例化
@Test
public void getIn() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 无参构造
Class<com.money.provider.User> userClass = com.money.provider.User.class;
com.money.provider.User user = userClass.newInstance();
System.out.println(user);
// 单参构造
Constructor<com.money.provider.User> constructor = userClass.getConstructor(String.class);
com.money.provider.User user1 = constructor.newInstance("money");
System.out.println(user1);
// 满参构造
Constructor<com.money.provider.User> constructor1 = userClass.getConstructor(String.class, Integer.class);
com.money.provider.User user2 = constructor1.newInstance("hahah", 1);
System.out.println(user2);
// 调用私有化的构造器反射实例化
Constructor<com.money.provider.User> declaredConstructor = userClass.getDeclaredConstructor(Integer.class);
// 打开私有修饰的访问权限
declaredConstructor.setAccessible(true);
com.money.provider.User user3 = declaredConstructor.newInstance(100);
System.out.println(user3);
}
注意:私有构造要使用getDeclaredConstructor方法,且需要把访问权限设置为true。
反射动态方法调用
Method类方法
public String getName() : 返回方法名
public int getModifiers() :获取方法的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号(一般配合 Modilier类)的 toString(int x)方法使用
public Class<?> getReturnType() :以Class类型,返回方法类型(一般配合Class类的getSimpleName() 方法使用) public Class<?>[] getParameterTypes() :返回方法的参数类型列表(一个方法的参数可能会有多个。)结果集一般配合Class类的getSimpleName() 方法使用
public Object invoke(Object obj,Object… args) : 调用方法
@Test
public void TestMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
com.money.provider.User user = new com.money.provider.User();
Class<? extends com.money.provider.User> aClass = user.getClass();
// 反射的无参方法调用
Method method = aClass.getMethod("hello");
Object invoke = method.invoke(user);
System.out.println(invoke);
// 反射有参方法
Method method1 = aClass.getMethod("hello",String.class);
Object invoke1 = method1.invoke(user, "money");
System.out.println(invoke1);
// 反射的私有方法
Method add = aClass.getDeclaredMethod("add", Integer.class, Integer.class);
add.setAccessible(true);
Object invoke2 = add.invoke(user, 1, 2);
System.out.println(invoke2);
}
反射读写属性
Field 类方法
public String getName() : 返回属性名
public int getModifiers() : 获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号,(一般配合 Modifier 类的toString(int x) 方法使用)
public Class<?> getType() : 以Class类型,返回属性类型(一般配合Class类的getSimpleName() 方法使用)
public void set(Object obj,Object value) : 设置属性值
public Object get(Object obj ) : 读取属性值
@Test
public void testField() throws NoSuchFieldException, IllegalAccessException {
com.money.provider.User user = new com.money.provider.User("money", 19);
Class<? extends com.money.provider.User> aClass = user.getClass();
// 反射存值
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(user,"测试");
System.out.println(user.getName());
// 反射获取值
Field name1 = aClass.getDeclaredField("name");
name1.setAccessible(true);
Object o = name1.get(user);
System.out.println(o);
System.out.println("=============================");
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
System.out.println(declaredField.get(user));
}
}
动态代理提前预习,学会看下面代码,思考反射在动态代理中的作用
invoke 是 Method 类中的一个方法。表示执行方法的调用
参数1:
Object ,表示对象,要执行这个对象的方法,即接口实现类的对象
参数2:
Object … args ,表示方法执行时的参数值
返回值:
Object : 方法执行后的返回值
字节码文件.getMethod(“name”,参数的类型);
示例:
package com.money.provider;
import com.money.common.domain.User;
import com.money.common.service.UserService;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class UserServiceImplTest {
@Test
public void test01(){
User user = new User();
user.setName("你好");
UserService userService = new UserServiceImpl();
User user1 = userService.getUser(user);
System.out.println(user1.getName());
}
@Test
public void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
user.setName("你好");
Method method = UserService.class.getMethod("getUser", User.class);
User invoke = (User)method.invoke(new UserServiceImpl(), user);
System.out.println(invoke.getName());
}
}