引言
反射和注解是Java的高级特性,是Spring、MyBatis等框架的基础。理解反射和注解的原理,对于掌握框架源码和设计模式至关重要。
一、Java反射机制
1.1 什么是反射?
定义:反射是Java在运行时动态获取类信息、调用方法、操作属性的能力。
1 2 3 4 5 6 7 8 9
| Person person = new Person(); person.setName("Alice");
Class<?> clazz = Class.forName("com.example.Person"); Object obj = clazz.getDeclaredConstructor().newInstance(); Method method = clazz.getMethod("setName", String.class); method.invoke(obj, "Alice");
|
1.2 获取Class对象的三种方式
1 2 3 4 5 6 7 8 9 10 11 12 13
| Class<Person> clazz1 = Person.class;
Person person = new Person(); Class<?> clazz2 = person.getClass();
Class<?> clazz3 = Class.forName("com.example.Person");
System.out.println(clazz1 == clazz2); System.out.println(clazz2 == clazz3);
|
1.3 反射创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Person { private String name; private int age; public Person() {} public Person(String name, int age) { this.name = name; this.age = age; } }
Class<?> clazz = Person.class; Person p1 = (Person) clazz.getDeclaredConstructor().newInstance();
Constructor<?> constructor = clazz.getConstructor(String.class, int.class); Person p2 = (Person) constructor.newInstance("Alice", 25);
|
1.4 反射访问字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class FieldDemo { private String privateField = "private"; public String publicField = "public"; public static void main(String[] args) throws Exception { FieldDemo obj = new FieldDemo(); Class<?> clazz = obj.getClass(); Field publicField = clazz.getField("publicField"); System.out.println(publicField.get(obj)); Field privateField = clazz.getDeclaredField("privateField"); privateField.setAccessible(true); System.out.println(privateField.get(obj)); privateField.set(obj, "modified"); System.out.println(obj.privateField); } }
|
1.5 反射调用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class MethodDemo { private void privateMethod(String msg) { System.out.println("Private: " + msg); } public String publicMethod(String msg) { return "Public: " + msg; } public static void main(String[] args) throws Exception { MethodDemo obj = new MethodDemo(); Class<?> clazz = obj.getClass(); Method publicMethod = clazz.getMethod("publicMethod", String.class); String result = (String) publicMethod.invoke(obj, "Hello"); System.out.println(result); Method privateMethod = clazz.getDeclaredMethod("privateMethod", String.class); privateMethod.setAccessible(true); privateMethod.invoke(obj, "World"); } }
|
1.6 反射获取类信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class ClassInfoDemo { public static void main(String[] args) { Class<?> clazz = Person.class; System.out.println("类名:" + clazz.getName()); System.out.println("简单类名:" + clazz.getSimpleName()); Field[] fields = clazz.getFields(); Field[] declaredFields = clazz.getDeclaredFields(); Method[] methods = clazz.getMethods(); Method[] declaredMethods = clazz.getDeclaredMethods(); Constructor<?>[] constructors = clazz.getConstructors(); Class<?> superclass = clazz.getSuperclass(); Class<?>[] interfaces = clazz.getInterfaces(); Annotation[] annotations = clazz.getAnnotations(); } }
|
二、反射应用场景
2.1 JDBC数据库连接
1 2 3 4 5 6
| Class.forName("com.mysql.cj.jdbc.Driver");
|
2.2 Spring IOC容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class SimpleIOC { private Map<String, Object> beans = new HashMap<>(); public void registerBean(String name, String className) throws Exception { Class<?> clazz = Class.forName(className); Object bean = clazz.getDeclaredConstructor().newInstance(); beans.put(name, bean); } public Object getBean(String name) { return beans.get(name); } }
SimpleIOC ioc = new SimpleIOC(); ioc.registerBean("userService", "com.example.UserService"); Object userService = ioc.getBean("userService");
|
2.3 通用工具类:对象复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class BeanUtil {
public static void copyProperties(Object source, Object target) throws Exception { Class<?> sourceClass = source.getClass(); Class<?> targetClass = target.getClass(); Field[] fields = sourceClass.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); Object value = field.get(source); try { Field targetField = targetClass.getDeclaredField(field.getName()); targetField.setAccessible(true); targetField.set(target, value); } catch (NoSuchFieldException e) { } } } }
PersonDTO dto = new PersonDTO(); PersonVO vo = new PersonVO(); BeanUtil.copyProperties(dto, vo);
|
三、Java注解
3.1 内置注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Override public String toString() { return "Person"; }
@Deprecated public void oldMethod() { }
@SuppressWarnings("unchecked") public void method() { List list = new ArrayList(); }
@FunctionalInterface public interface MyFunction { void run(); }
|
3.2 元注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Target(ElementType.METHOD) @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.CLASS) @Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Repeatable(Roles.class)
|
3.3 自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value() default ""; String name() default "default"; int age() default 0; String[] tags() default {}; }
public class User { @MyAnnotation(value = "test", name = "Alice", age = 25) public void method1() {} @MyAnnotation("simple") public void method2() {} }
|
3.4 解析注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class AnnotationParser { public static void main(String[] args) throws Exception { Class<?> clazz = User.class; if (clazz.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation anno = clazz.getAnnotation(MyAnnotation.class); System.out.println(anno.value()); } Method method = clazz.getMethod("method1"); if (method.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation anno = method.getAnnotation(MyAnnotation.class); System.out.println("value: " + anno.value()); System.out.println("name: " + anno.name()); System.out.println("age: " + anno.age()); } Annotation[] annotations = method.getAnnotations(); for (Annotation anno : annotations) { System.out.println(anno); } } }
|
四、注解实战应用
4.1 自定义参数校验注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface NotNull { String message() default "字段不能为空"; }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Length { int min() default 0; int max() default Integer.MAX_VALUE; String message() default "长度不符合要求"; }
public class UserDTO { @NotNull(message = "用户名不能为空") @Length(min = 3, max = 20, message = "用户名长度必须在3-20之间") private String username; @NotNull(message = "密码不能为空") @Length(min = 6, message = "密码至少6位") private String password; }
public class Validator { public static void validate(Object obj) throws Exception { Class<?> clazz = obj.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); Object value = field.get(obj); if (field.isAnnotationPresent(NotNull.class)) { if (value == null) { NotNull anno = field.getAnnotation(NotNull.class); throw new IllegalArgumentException(anno.message()); } } if (field.isAnnotationPresent(Length.class) && value instanceof String) { Length anno = field.getAnnotation(Length.class); String str = (String) value; if (str.length() < anno.min() || str.length() > anno.max()) { throw new IllegalArgumentException(anno.message()); } } } } }
UserDTO user = new UserDTO(); user.setUsername("ab"); Validator.validate(user);
|
4.2 自定义权限注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RequirePermission { String[] value(); }
public class UserService { @RequirePermission({"user:read", "user:list"}) public List<User> listUsers() { return new ArrayList<>(); } @RequirePermission("user:delete") public void deleteUser(Long id) { } }
public class PermissionChecker { public static void checkPermission(Method method, Set<String> userPermissions) { if (method.isAnnotationPresent(RequirePermission.class)) { RequirePermission anno = method.getAnnotation(RequirePermission.class); String[] requiredPermissions = anno.value(); for (String perm : requiredPermissions) { if (!userPermissions.contains(perm)) { throw new SecurityException("权限不足:需要" + perm); } } } } }
|
4.3 自定义ORM框架
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String value(); }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String value(); }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Id { }
@Table("t_user") public class User { @Id @Column("id") private Long id; @Column("username") private String username; @Column("age") private Integer age; }
public class SimpleORM { public String generateInsertSQL(Object obj) throws Exception { Class<?> clazz = obj.getClass(); Table table = clazz.getAnnotation(Table.class); String tableName = table.value(); List<String> columns = new ArrayList<>(); List<Object> values = new ArrayList<>(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Column.class)) { Column column = field.getAnnotation(Column.class); columns.add(column.value()); field.setAccessible(true); values.add(field.get(obj)); } } String sql = String.format("INSERT INTO %s (%s) VALUES (%s)", tableName, String.join(", ", columns), values.stream().map(v -> "?").collect(Collectors.joining(", ")) ); return sql; } }
User user = new User(); user.setId(1L); user.setUsername("Alice"); user.setAge(25);
SimpleORM orm = new SimpleORM(); String sql = orm.generateInsertSQL(user);
|
五、动态代理
5.1 JDK动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public interface UserService { void addUser(String name); String getUser(Long id); }
public class UserServiceImpl implements UserService { @Override public void addUser(String name) { System.out.println("添加用户:" + name); } @Override public String getUser(Long id) { return "User-" + id; } }
public class LogInvocationHandler implements InvocationHandler { private Object target; public LogInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用方法:" + method.getName()); System.out.println("参数:" + Arrays.toString(args)); Object result = method.invoke(target, args); System.out.println("返回值:" + result); return result; } }
UserService target = new UserServiceImpl(); UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new LogInvocationHandler(target) );
proxy.addUser("Alice");
|
5.2 CGLIB动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class UserService { public void addUser(String name) { System.out.println("添加用户:" + name); } }
public class CglibProxy implements MethodInterceptor { private Object target; public Object getProxy(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("调用方法:" + method.getName()); Object result = method.invoke(target, args); System.out.println("调用完成"); return result; } }
UserService target = new UserService(); CglibProxy cglibProxy = new CglibProxy(); UserService proxy = (UserService) cglibProxy.getProxy(target); proxy.addUser("Bob");
|
5.3 JDK代理 vs CGLIB代理
| 特性 |
JDK动态代理 |
CGLIB代理 |
| 要求 |
必须有接口 |
不需要接口 |
| 原理 |
实现接口 |
继承目标类 |
| 性能 |
较快 |
较慢(创建时) |
| final方法 |
可以代理 |
无法代理 |
| Spring默认 |
有接口时使用 |
无接口时使用 |
六、反射的性能优化
6.1 缓存Class对象
1 2 3 4 5 6 7 8 9 10
| for (int i = 0; i < 10000; i++) { Class<?> clazz = Class.forName("com.example.User"); }
Class<?> clazz = Class.forName("com.example.User"); for (int i = 0; i < 10000; i++) { }
|
6.2 缓存Method对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class MethodCache { private static final Map<String, Method> cache = new ConcurrentHashMap<>(); public static Method getMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) throws NoSuchMethodException { String key = clazz.getName() + "#" + methodName; return cache.computeIfAbsent(key, k -> { try { return clazz.getMethod(methodName, paramTypes); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } }); } }
|
6.3 使用MethodHandle(JDK 7+)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class MethodHandleDemo { public static void main(String[] args) throws Throwable { Person person = new Person(); MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodType mt = MethodType.methodType(void.class, String.class); MethodHandle mh = lookup.findVirtual(Person.class, "setName", mt); mh.invoke(person, "Alice"); } }
|
七、面试高频问题
7.1 反射的优缺点?
优点:
- 灵活性高,运行时动态操作
- 框架开发的基础(Spring、MyBatis)
- 可以访问私有成员
缺点:
7.2 如何提高反射性能?
- 缓存Class、Method、Field对象
- 使用setAccessible(true)减少安全检查
- 使用MethodHandle替代反射
- 批量操作减少反射调用次数
7.3 注解的原理?
注解本质是一个继承了Annotation接口的接口,JVM在加载类时会解析注解信息并存储在Class对象中,通过反射可以获取注解信息。
总结
反射和注解是Java的核心特性:
- 反射:动态获取类信息、创建对象、调用方法
- 注解:元数据标记,通过反射解析
- 应用:框架开发、AOP、ORM、参数校验
- 优化:缓存、MethodHandle、减少反射调用
参考资料