目录
- 1、介绍
- 1.1、举例
- 1.2、作用
- 2、核心类
- 3、应用场景
- 3.1、基本反射操作
- 3.2、动态加载类
- 3.3、调用私有方法(测试时常用)
- 3.4、jsON/XML序列化与反序列化
- 3.4.1.json序列化
- 3.4.2.xml实现
- 3.5、反射实现依赖注入
- 1. 简单依赖注入实现
- 2. 依赖注入原理
- 3.6、反射实现动态代理
- 1. JDK动态代理示例
- 2. CGLIB动态代理示例
- 3.7、反射实现注解处理
- 1. 定义自定义注解
- 2. 使用反射处理注解
- 3. 进阶注解处理
- 3.8、代码提示、idea自动补全
- 4、反射的优缺点
- 5、总结
1、介绍
反射(Reflection)是Java语言的一个特性,它允许程序在运行时动态地获取类的信息并操作类或对象的属性、方法和构造器。
1.1、举例
想象你有一个密封的盒子(类),正常情况下你只能通过盒子上的按钮(公共方法)来操作它。而反射就像是一把X光扫描仪,可以让你不用打开盒子就能看到里面的所有结构(私有字段、方法等),甚至可以绕过正常的操作方式直接控制内部部件。
什么时候需要用到反射呢?
举个生动例子:
class GameCharacter { private int health = 100; // 血量 private String name; public void attack() { /* 攻击逻辑 */ } private void cheat() { health = 9999; } // 作弊方法 }
没有反射时:
你只能调用 attack()方法
无法修改血量health
无法调用 cheat()方法
使用反射后:
// 获取角色类的X光照片 Class<?> clazz = GameCharacter.class; // 找到血量字段并修改(无视private) Field healthField = clazz.getDeclaredField("health"); healthField.setAccessible(true); // 万能钥匙开锁 healthField.set(character, 9999); // 修改血量 // 找到作弊方法并调用 Method cheatMethod = clazz.getDeclaredMethod("cheat"); cheatMethod.setAccessible(true); cheatMethod.invoke(character); // 执行作弊
这就好比在游戏运行时突然获得了修改角色属性的能力!
1.2、作用
2、核心类
Java反射主要涉及以下几个核心类:
Class:表示类的元数据
Field:表示类的字段
Method:表示类的方法
Constructor:表示类的构造器
3、应用cEXoWQqtWE场景
3.1、基本反射操作
import java.lang.reflect.*; public class ReflectionDemo { public static void main(String[] args) throws Exception { // 获取Class对象的三种方式 Class<?> clazz1 = Class.forName("java.lang.String"); Class<?> clazz2 = String.class; Class<?> clazz3 = "hello".getClass(); System.out.println("类名: " + clazz1.getName()); System.out.println("简单类名: " + clazz1.getSimpleName()); // 获取所有公共方法 System.out.println("\n公共方法:"); Method[] methods = clazz1.getMethods(); for (Method method : methods) { System.out.println(method.getName()); } // 获取所有声明的字段(包括私有) System.out.println("\n所有字段:"); Field[] fields = clazz1.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName()); } // 创建实例并调用方法 String str = (String) clazz1.getConstructor(String.class).newInstance("Hello Reflection"); Method lengthMethod = clazz1.getMethod("length"); int length = (int) lengthMethod.invoke(str); System.out.println("\n字符串长度: " + length); } }
3.2、动态加载类
// 根据配置文件动态加载类 public class PluginManager { public void loadPlugin(String className) throws Exception { Class<?> pluginClass = Class.forName(className); Object plugin = pluginClass.newInstance(); if (plugin instanceof Runnable) { ((Runnable) plugin).run(); } } } // 使用 PluginManager manager = new PluginManager(); manager.loadPlugin("com.example.MyPlugin"); // 类名可以从配置文件中读取
3.3、调用私有方法(测试时常用)
public class SecretClass { private String secretMethod(String input) { return "Secret: " + input; } } // 测试类中使用反射调用私有方法 public class SecretTest { public static void main(String[] args) throws Exception { SecretClass instance = new SecretClass(); Class<?> clazz = instance.getClass(); Method secretMethod = clazz.getDeclaredMethod("secretMethod", String.class); secretMethod.setAccessible(true); // 突破私有限制 String result = (String) secretMethod.invoke(instance, "Hello"); System.out.println(result); // 输出: Secret: Hello } }
3.4、JSON/XML序列化与反序列化
3.4.1.json序列化
// 简单的JSON序列化工具(简化版) public class JsonSerializer { public static String toJson(Object obj) throws Exception { Class<?> clazz = obj.getClass(); Field[] fields = clazz.getDeclaredFields(); StringBuilder json = new StringBuilder("{"); for (Field field : fields) { field.setAccessible(true); json.append("\"").append(field.getName()).append("\":") .append("\"").append(field.get(obj)).append("\","); } json.deleteCharAt(json.length() - 1).append("}"); return json.toString(); } } // 使用 class Person { private String name = "Alice"; private int age = 25; } Person person = new Person(); System.out.println(JsonSerializer.toJson(person)); // 输出: {"name":"Alice","age":25}
3.4.2.xml编程实现
import java.lang.reflect.*; import java.util.*; public class XmlSerializer { public static String toXml(Object obj) throws Exception { if (obj == null) return "<null/>"; Class<?> clazz = obj.getClass(); StringBuilder xml = new StringBuilder(); // 处理基本类型 if (obj instanceof Number || obj instanceof Boolean || obj instanceof String) { return "<value>" + obj.toString() + "</value>"; } // 处理数组 if (clazz.isArray()) { xml.append("<array type=\"").append(clazz.getComponentType().getSimpleName()).append("\">"); int length = Array.getLength(obj); for (int i = 0; i < length; i++) { xml.append(toXml(Array.get(obj, i))); } xml.append("</array>"); return xml.toString(); } // 处理集合 if (obj instanceof Collection) { Collection<?> collection = (Collection<?>) obj; xml.append("<collection>"); for (Object item : collection) { xml.append(toXml(item)); } xml.append("</collection>"); return xml.toString(); } // 处理普通对象 xml.append("<").append(clazz.getSimpleName()).append(">"); for (Field field : clazz.getDeclaredFields()) { if (Modifier.isTransient(field.getModifiers())) continue; field.setAccessible(true); Object value = field.get(obj); xml.append("<").append(field.getName()).append(">") .append(toXml(value)) .append("</").append(field.getName()).append(">"); } xml.append("</").append(clazz.getSimpleName()).append(">"); return xml.toString(); } public static void main(String[] args) throws Exception { class Product { private String id = "P1001"; private String name = "Laptop";
输出:
<Product><id>P1001</id><name>Laptop</name><price>999.99</price><tags><array type="String">&jslt;value>electronics</value><value>computer</value></array></tags></Product>
3.5、反射实现依赖注入
依赖注入是框架(如Spring)中广泛使用的设计模式,它通过反射机制动态地将依赖对象注入到目标对象中。
1. 简单依赖注入实现
import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; // 模拟一个简单的IoC容器 public class SimpleContainer { private Map<String, Object> beans = new HashMap<>(); // 注册Bean public void registerBean(String name, Object bean) { beans.put(name, bean); } // 依赖注入 public void injectDependencies() throws Exception { for (Object bean : beans.values()) { // 获取Bean的所有字段 Field[] fields = bean.getClass().getDeclaredFields(); for (Field field : fields) { // 检查是否有@Autowired注解(这里简化处理) if (field.getAnnotation(Autowired.class) != null) { // 获取字段类型 Class<?> fieldType = field.getType(); // 查找匹配的依赖Bean Object dependency = findDependency(fieldType); if (dependency != null) { // 突破私有访问限制 field.setAccessible(true); // 注入依赖 field.set(bean, dependency); } } } } } // 查找匹配的依赖 private Object findDependency(Class<?> type) { for (Object bean : beans.values()) { if (type.isAssignableFrom(bean.getClass())) { return bean; } } return null; } } // 自定义Autowired注解 @interface Autowired {} // 使用示例 class ServiceA {} class ServiceB { @Autowired private ServiceA serviceA; // 将被自动注入 public void showDependency() { System.out.println("ServiceB中的ServiceA依赖: " + serviceA); } } public class DITest { public static void main(String[] args) throws Exception { SimpleContainer container = new SimpleContainer(); container.registerBean("serviceA", new ServiceA()); container.registerBean("serviceB", new ServiceB()); container.injectDependencies(); ServiceB serviceB = (ServiceB) container.getBean("serviceB"); serviceB.showDependency(); } }
2. 依赖注入原理
Spring框架的依赖注入核心流程:
扫描类路径,通过反射获取类的元信息
解析@Component、@Service等注解
解析构造器或字段上的@Autowired注解
通过反射创建Bean实例
通过反射将依赖注入到目标字段或构造器中
3.6、反射实现动态代理
动态代理是AOP(面向切面编程)的基础,它允许在运行时动态创建代理对象。
1. JDK动态代理示例
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 业务接口 interface UserService { void addUser(String name); void deleteUser(String name); } // 实际业务实现 class UserServiceImpl implements UserService { public void addUser(String name) { System.out.println("添加用户: " + name); } public void deleteUser(String name) { System.out.println("删除用户: " + name); } } // 代理处理器 class LoggingHandler implements InvocationHandler { private Object target; // 被代理对象 public LoggingHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置增强 System.out.println("准备执行: " + method.getName()); // 反射调用原始方法 Object result = method.invoke(target, args); // 后置增强 System.out.println("执行完成: " + method.getName()); return result; } } public class DynamicProxyDemo { public static void main(String[] args) { UserService realService = new UserServiceImpl(); // 创建代理对象 UserService proxyService = (UserService) Proxy.newproxyInstance( UserService.class.getClassLoader(), new Class[]{UserService.class}, new LoggingHandler(realService) ); // 通过代理调用方法 proxyService.addUser("张三"); proxyService.deleteUser("李四"); } } 输出: 准备执行: addUser 添加用户: 张三 执行完成: addUser 准备执行: deleteUser 删除用户: 李四 执行完成: deleteUser
2. CGLIB动态代理示例
当目标类没有实现接口时,可以使用CGLIB库:
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; class ProductService { public void saveProduct(String name) { System.out.println("保存产品: " + name); } } class ProductMethodInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("CGLIB代理前置处理"); Object result = proxy.invokeSuper(obj, args); System.out.println("CGLIB代理后置处理"); return result; } } public class CglibProxyDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(ProductService.class); enhancer.setCallback(new ProductMethodInterceptor()); ProductService proxy = (ProductService) enhancer.create(); proxy.saveProduct("笔记本电脑"); } } 输出: CGLIB代理前置处理 保存产品: 笔记本电脑 CGLIB代理后置处理
3.7、反射实现注解处理
Java反射API提供了以下关键方法来处理注解:
getAnnotation(Class<T>) - 获取指定类型的注解
getAnnotations
()
- 获取所有注解isAnnotationPresent(Class<?>) - 检查是否存在指定注解
1. 定义自定义注解
import java.lang.annotation.*; // 表注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @interface Table { String name(); } // 列注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @interface Column { String name(); String type(); }
2. 使用反射处理注解
代码示例如下:
import java.lang.reflect.Field; // 应用注解的实体类 @Table(name = "user_table") class User { @Column(name = "user_id", type = "bigint") private Long id; @Column(name = "user_name", type = "varchar(50)") private String name; @Column(name = "user_age", type = "int") private Integer age; // 非持久化字段(无Column注解) private transient String temp; } public class AnnotationProcessor { public static void main(String[] args) { // 获取类注解 Class<User> userClass = User.class; Table tableAnnotation = userClass.getAnnotation(Table.class); if (tableAnnotation != null) { System.out.println("表名: " + tableAnnotation.name()); // 生成建表SQL StringBuilder sql = new StringBuilder(); sql.append("CREATE TABLE ").append(tableAnnotation.name()).append("(\n"); // 处理字段注解 Field[] fields = userClass.getDeclaredFields(); for (Field field : fields) { Column columnAnnotation = field.getAnnotation(Column.class); if (columnAnnotation != null) { sql.append(" ").append(columnAnnotation.name()) .append(" ").append(columnAnnotation.type()) .append(",\n"); } } sql.delete(sql.length()-2, sql.length()); // 删除最后的逗号和换行 sql.append("\n);"); System.out.println("生成的SQL:\n" + sql); } } } 输出: 表名: user_table 生成的SQL: CREATE TABLE user_table( user_id bigint, user_name varchar(50), user_age int );
3. 进阶注解处理
1. 方法级注解与处理
import java.lang.annotation.*; import java.lang.reflect.Method; // 定义权限注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface Permission { String[] roles() default {}; } // 服务类 class AdminService { @Permission(roles = {"admin", "superadmin"}) public void deleteUser(String username) { System.out.println("删除用户: " + username); } @Permission(roles = {"user", "admin"}) public void viewProfile(String username) { System.out.println("查看用户资料: " + username); } public void publicMethod() { System.out.println("公开方法,无需权限"); } } public class PermissionProcessor { public static void main(String[] args) throws Exception { // 模拟当前用户角色 String currentRole = "user"; AdminService service = new AdminService(); Method[] methods = service.getClass().getMethods(); for (Method method : methods) { if (method.isAnnotationPresent(Permission.class)) { Permission permission = method.getAnnotation(Permission.class); boolean hASPermission = false; // 检查用户是否有权限 for (String role : permission.roles()) { if (role.equals(currentRole)) { hasPermission = true; break; } } if (hasPermission) { System.out.println("允许执行: " + method.getName()); method.invoke(service, "testUser"); } else { System.out.println("拒绝访问: " + method.getName() + ",需要角色: " + String.join(",", permission.roles())); } } else { // 没有权限注解的方法可以直接执行 System.out.println("执行无权限限制方法: " + method.getName()); method.invoke(service); } } } } 输出: 允许执行: viewProfile 查看用户资料: testUser 拒绝访问: deleteUser,需要角色: admin,superadmin 执行无权限限制方法: publicMethod 公开方法,无需权限
2. 参数级注解与验证
import java.lang.annotation.*; import java.lang.reflect.*; import java.util.*; // 参数验证注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) @interface Validate { int min() default 0; int max() default Integer.MAX_VALUE; String pattern() default ""; } class UserService { public void createUser( @Validate(min = 3, max = 20) String username, @Validate(min = 6, pattern = ".*[0-9].*") String password) { System.out.println("创建用户: " + username); } } public class ValidationProcessor { public static void invokeWithValidation(Object target, Method method, Object... args) throws Exception { Parameter[] parameters = method.getParameters(); for (int i = 0; i < parameters.length; i++) { Validate validate = parameters[i].getAnnotation(Validate.class); if (validate != null) { Object arg = args[i]; if (arg instanceof String) { String value = (String) arg; // 检查长度 if (value.length() < validate.min()) { throw new IllegalArgumentException( parameters[i].getName() + " 长度不能小于 " + validate.min()); } if (value.length() > validate.max()) { throw new IllegalArgumentException( parameters[i].getName() + " 长度不能大于 " + validate.max()); } // 检查正则表达式 if (!validate.pattern().isEmpty() && !value.matches(validate.pattern())) { throw new IllegalArgumentException( parameters[i].getName() + " 不符合格式要求"); } } } } // 所有验证通过,调用方法 method.invoke(target, args); } public static void main(String[] args) throws Exception { UserService service = new UserService(); Method method = service.getClass().getMethod("createUser", String.class, String.class); // 测试用例 try { invokeWithValidation(service, method, "ab", "123456"); // 用户名太短 } catch (IllegalArgumentException e) { System.out.println("验证失败: " + e.getMessage()); } try { invokeWithValidation(service, method, "validUser", "simple"); // 密码不符合格式 } catch (IllegalArgumentException e) { System.out.println("验证失败: " + e.getMessage()); } cEXoWQqtWE // 成功案例 invokeWithValidation(service, method, "validUser", "pass123"); } } 输出结果: 验证失败: username 长度不能小于 3 验证失败: password 不符合格式要求 创建用户: validUser
3. 模拟Spring MVC的控制器处理
import java.lang.annotation.*; import java.lang.reflect.*; import java.util.*; // 模拟Spring MVC注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Controller @interface Controller { String value() default ""; } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @RequestMapping @interface RequestMapping { String path(); String method() default "GET"; } // 控制器类 @Controller("/user") class UserController { @RequestMapping(path = "/list编程客栈", method = "GET") public List<String> listUsers() { return Arrays.asList("Alice", "Bob", "Charlie"); } @RequestMapping(path = "/add", method = "POST") public String addUser(String username) { return "添加用户成功: " + username; } } public class MvcSimulator { private Map<String, Method> routeMap = new HashMap<>(); public void init() { // 扫描所有Controller类 Class<?>[] controllers = {UserController.class}; // 实际框架会扫描包 for (Class<?> controller : controllers) { Controller controllerAnnotation = controller.getAnnotation(Controller.class); String basePath = controllerAnnotation.value(); // 处理每个方法 for (Method method : controller.getDeclaredMethods()) { if (method.isAnnotationPresent(RequestMapping.class)) { RequestMapping mapping = method.getAnnotation(RequestMapping.class); String fullPath = basePath + mapping.path(); routeMap.put(mapping.method() + ":" + fullPath, method); } } } } public Object handleRequest(String httpMethod, String path, Object... args) throws Exception { String key = httpMethod + ":" + path; Method method = routeMap.get(key); if (method != null) { // 实际框架会处理参数绑定等复杂逻辑 return method.invoke(method.getDeclaringClass().newInstance(), args); } throw new RuntimeException("404 Not Found"); } public static void main(String[] args) throws Exception { MvcSimulator simulator = new MvcSimulator(); simulator.init(); // 模拟HTTP请求 Object result1 = simulator.handleRequest("GET", "/user/list"); System.out.println("GET /user/list => " + result1); Object result2 = simulator.handleRequest("POST", "/user/add", "David"); System.out.println("POST /user/add => " + result2); try { simulator.handleRequest("GET", "/not/exist"); } catch (Exception e) { System.out.println("GET /not/exist => " + e.getMessage()); } } } 输出: GET /user/list => [Alice, Bob, Charlie] POST /user/add => 添加用户成功: David GET /not/exist => 404 Not Found
3.8、代码提示、idea自动补全
IDE功能:如代码提示、自动补全等功能利用反射获取类信息
实现代码提示和自动补全主要需要以下反射操作:
获取类的所有公共方法(getMethods())
获取类的所有声明方法(getDeclaredMethods())
获取方法的参数信息(getParameterTypes())
获取类的字段信息(getFields(), getDeclaredFields())
获取类的构造函数(getConstructors())
1. 类成员自动补全
import java.lang.reflect.*; import java.util.*; public class CodeCompletion { private static final Set<String> JAVA_KEYWORDS = new HashSet<>(Arrays.asList( "public", "private", "protected", "static", "void", "class", "interface" )); public static List<String> getClassSuggestions(Class<?> clazz, String prefix) { List<String> suggestions = new ArrayList<>(); // 获取公共方法 for (Method method : clazz.getMethods()) { if (method.getName().startsWith(prefix) { suggestions.add(method.getName() + "()"); } } // 获取公共字段 for (Field field : clazz.getFields()) { if (field.getName().startsWith(prefix)) { suggestions.add(field.getName()); } } return suggestions; } public static List<String> getContextAwareSuggestions(Class<?> clazz, String context, String prefix) { List<String> suggestions = new ArrayList<>(); if (context.endsWith(".")) { // 对象成员提示 try { Field field = clazz.getField(context.substring(0, context.length()-1)); return getClassSuggestions(field.getType(), prefix); } catch (Exception e) { // 处理异常 } } else if (JAVA_KEYWORDS.contains(context)) { // 关键字后不提示 return suggestions; } else { // 类静态成员提示 return getClassSuggestions(clazz, prefix); } return suggestions; } public static void main(String[] args) { Class<?> stringClass = String.class; System.out.println("String类以'comp'开头的方法/字段:"); System.out.println(getClassSuggestions(stringClass, "comp")); System.out.println("\nString类以'to'开头的方法/字段:"); System.out.println(getClassSuggestions(stringClass, "to")); } } 输出: String类以'comp'开头的方法/字段: [compareTo(), compareToIgnoreCase()] String类以'to'开头的方法/字段: [toCharArray(), toLowerCase(), toLowerCase(), toUpperCase(), toUpperCase(), toString(), toLowerCase(), toUpperCase()]
2. 方法参数提示
import java.lang.reflect.*; import java.util.*; public class MethodParameterHint { public static Map<String, List<String>> getMethodParameterHints(Class<?> clazz) { Map<String, List<String>> hints = new HashMap<>(); for (Method method : clazz.getMethods()) { List<String> params = new ArrayList<>(); for (Parameter param : method.getParameters()) { params.add(param.getType().getSimpleName() + " " + param.getName()); } String methodKey = method.getName() + "(" + String.join(", ", params) + ")"; hints.put(methodKey, params); } return hints; } public static void printMethodHints(Class<?> clazz, String methodPrefix) { System.out.println("方法名以'" + methodPrefix + "'开头的方法签名:"); for (Method method : clazz.getMethods()) { if (method.getName().startsWith(methodPrefix)) { System.out.print(method.getName() + "("); Parameter[] params = method.getParameters(); for (int i = 0; i < params.length; i++) { if (i > 0) System.out.print(", "); System.out.print(params[i].getType().getSimpleName() + " " + params[i].getName()); } System.out.println(")"); } } } public static void main(String[] args) { Class<?> listClass = List.class; System.out.println("List接口所有方法参数提示:"); Map<String, List<String>> hints = getMethodParameterHints(listClass); hints.forEach((k, v) -> System.out.println(k)); System.out.println("\n---\n"); printMethodHints(listClass, "add"); } } 输出: List接口所有方法参数提示: add(E e) addAll(Collection<? extends E> c) ... add(int index, E element) 方法名以'add'开头的方法签名: add(E e) add(int index, E element) addAll(Collection<? extends E> c) addAll(int index, Collection<? extends E> c)
4、反射的优缺点
优点:
极大的灵活性,可以在运行时动态操作
可以访问类的私有成员(突破封装)
适合开发通用框架和工具
缺点:
性能开销较大(比直接调用慢)
破坏封装性,可能带来安全问题
代码可读性降低,调试困难
5、总结
记住:反射是Java的"元"能力,强大但应慎用,就像超能力不能随便在公共场合使用一样!
到此这篇关于java中反射详解及实际应用场景的文章就介绍到这了,更多相关java反射详解内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论