🎯 本文将带您深入理解Java反射机制的工作原理,通过实际案例掌握反射的高级应用。文末配有面试高频考点,助您快速提升!
一、反射机制概述
1.1 什么是反射
1.2 反射的应用场景
场景 | 说明 | 示例 |
---|---|---|
框架开发 | 动态创建对象 | Spring IOC |
动态代理 | 运行时增强 | AOP |
注解处理 | 运行时解析 | Lombok |
泛型擦除 | 获取泛型信息 | Jackson |
二、Class类与类加载
2.1 获取Class对象
public class ClassDemo {
public static void main(String[] args) {
// 1. 类名.class
Class<String> clazz1 = String.class;
// 2. 对象.getClass()
String str = "Hello";
Class<?> clazz2 = str.getClass();
// 3. Class.forName()
try {
Class<?> clazz3 = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 4. 类加载器
try {
ClassLoader loader = ClassDemo.class.getClassLoader();
Class<?> clazz4 = loader.loadClass("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2.2 类加载过程
public class ClassLoadingDemo {
static {
System.out.println("静态初始化块执行");
}
public static void main(String[] args) {
// 演示类加载过程
try {
// 1. 加载
Class<?> clazz = Class.forName("com.example.MyClass",
true, // 是否初始化
ClassLoadingDemo.class.getClassLoader()); // 使用的类加载器
// 2. 链接(验证、准备、解析)
// 3. 初始化
Object obj = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、反射API详解
3.1 构造器操作
public class ConstructorDemo {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("java.lang.String");
// 获取所有公共构造器
Constructor<?>[] constructors = clazz.getConstructors();
// 获取所有构造器(包括私有)
Constructor<?>[] allConstructors =
clazz.getDeclaredConstructors();
// 获取特定构造器
Constructor<?> constructor =
clazz.getDeclaredConstructor(byte[].class);
// 创建实例
constructor.setAccessible(true); // 访问私有构造器
Object obj = constructor.newInstance(new byte[]{65, 66, 67});
System.out.println(obj); // 输出:ABC
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2 方法操作
public class MethodDemo {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("java.lang.String");
// 获取所有公共方法
Method[] methods = clazz.getMethods();
// 获取所有方法(包括私有)
Method[] allMethods = clazz.getDeclaredMethods();
// 获取特定方法
Method method = clazz.getDeclaredMethod(
"substring", int.class, int.class);
// 调用方法
String str = "Hello World";
method.setAccessible(true); // 访问私有方法
Object result = method.invoke(str, 0, 5);
System.out.println(result); // 输出:Hello
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.3 字段操作
public class FieldDemo {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("java.lang.String");
// 获取所有公共字段
Field[] fields = clazz.getFields();
// 获取所有字段(包括私有)
Field[] allFields = clazz.getDeclaredFields();
// 获取特定字段
Field field = clazz.getDeclaredField("value");
// 修改字段值
String str = "Hello";
field.setAccessible(true); // 访问私有字段
byte[] value = (byte[]) field.get(str);
// 修改为新值
field.set(str, new byte[]{'H', 'i'});
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、反射性能优化
4.1 性能开销分析
public class ReflectionPerformance {
private static final int ITERATIONS = 1000000;
public static void main(String[] args) throws Exception {
// 1. 直接调用
long start = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
String str = "Hello";
str.substring(0, 2);
}
long directTime = System.nanoTime() - start;
// 2. 反射调用
Method method = String.class.getMethod("substring", int.class, int.class);
start = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
String str = "Hello";
method.invoke(str, 0, 2);
}
long reflectTime = System.nanoTime() - start;
// 3. 反射调用(关闭安全检查)
method.setAccessible(true);
start = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
String str = "Hello";
method.invoke(str, 0, 2);
}
long reflectFastTime = System.nanoTime() - start;
System.out.printf("直接调用:%d ns%n", directTime / ITERATIONS);
System.out.printf("反射调用:%d ns%n", reflectTime / ITERATIONS);
System.out.printf("优化反射:%d ns%n", reflectFastTime / ITERATIONS);
}
}
4.2 优化策略
public class ReflectionOptimization {
// 1. 缓存反射对象
private static final Map<String, Method> methodCache =
new ConcurrentHashMap<>();
public static Method getMethod(String className, String methodName,
Class<?>... paramTypes) throws Exception {
String key = className + "#" + methodName;
return methodCache.computeIfAbsent(key, k -> {
try {
Class<?> clazz = Class.forName(className);
Method method = clazz.getDeclaredMethod(methodName, paramTypes);
method.setAccessible(true);
return method;
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
// 2. 使用setAccessible提高性能
public static void optimizeAccess(AccessibleObject object) {
if (!object.isAccessible()) {
object.setAccessible(true);
}
}
// 3. 批量操作优化
public static void batchOperation(List<Object> objects,
String methodName) throws Exception {
if (objects.isEmpty()) return;
// 获取方法只需一次
Class<?> clazz = objects.get(0).getClass();
Method method = clazz.getDeclaredMethod(methodName);
method.setAccessible(true);
// 批量调用
for (Object obj : objects) {
method.invoke(obj);
}
}
}
五、实战案例:构建简易IOC容器
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Component {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Autowired {
}
// IOC容器实现
public class SimpleIOC {
private Map<String, Object> beanMap = new HashMap<>();
public SimpleIOC(String basePackage) throws Exception {
scanPackage(basePackage);
}
// 扫描包
private void scanPackage(String basePackage) throws Exception {
// 获取包下所有类
String path = basePackage.replace('.', '/');
ClassLoader classLoader = getClass().getClassLoader();
URL url = classLoader.getResource(path);
File dir = new File(url.getFile());
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
scanPackage(basePackage + "." + file.getName());
} else if (file.getName().endsWith(".class")) {
String className = basePackage + "." +
file.getName().replace(".class", "");
Class<?> clazz = Class.forName(className);
// 处理@Component注解
if (clazz.isAnnotationPresent(Component.class)) {
Component component =
clazz.getAnnotation(Component.class);
String beanName = component.value();
if (beanName.isEmpty()) {
beanName = lowerFirstChar(clazz.getSimpleName());
}
Object bean = clazz.newInstance();
beanMap.put(beanName, bean);
}
}
}
// 处理依赖注入
for (Object bean : beanMap.values()) {
injectFields(bean);
}
}
// 依赖注入
private void injectFields(Object bean) throws Exception {
Class<?> clazz = bean.getClass();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
String beanName = lowerFirstChar(field.getType().getSimpleName());
Object value = beanMap.get(beanName);
field.set(bean, value);
}
}
}
// 获取Bean
public Object getBean(String name) {
return beanMap.get(name);
}
private String lowerFirstChar(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
}
// 使用示例
@Component
public class UserService {
@Autowired
private UserDao userDao;
public void save() {
userDao.save();
}
}
@Component
public class UserDao {
public void save() {
System.out.println("保存用户");
}
}
// 测试
public class IOCTest {
public static void main(String[] args) throws Exception {
SimpleIOC ioc = new SimpleIOC("com.example");
UserService userService = (UserService) ioc.getBean("userService");
userService.save();
}
}
六、注解与反射
6.1 注解处理
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Api {
String value() default "";
String description() default "";
int version() default 1;
}
// 注解处理器
public class AnnotationProcessor {
public static void processClass(Class<?> clazz) {
// 处理类上的注解
if (clazz.isAnnotationPresent(Api.class)) {
Api api = clazz.getAnnotation(Api.class);
System.out.printf("API名称:%s,描述:%s,版本:%d%n",
api.value(), api.description(), api.version());
}
// 处理方法上的注解
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Api.class)) {
Api api = method.getAnnotation(Api.class);
System.out.printf("方法:%s,描述:%s%n",
method.getName(), api.description());
}
}
}
}
// 使用示例
@Api(value = "用户服务", description = "处理用户相关操作", version = 2)
public class UserController {
@Api(description = "创建新用户")
public void createUser() {
// 创建用户逻辑
}
@Api(description = "获取用户信息")
public void getUser() {
// 获取用户逻辑
}
}
6.2 泛型与反射
public class GenericReflection {
// 获取泛型参数类型
public static void analyzeGeneric(Class<?> clazz) {
// 获取父类泛型信息
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType type = (ParameterizedType) genericSuperclass;
Type[] arguments = type.getActualTypeArguments();
for (Type argument : arguments) {
System.out.println("泛型类型:" + argument);
}
}
// 获取接口泛型信息
Type[] genericInterfaces = clazz.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType type = (ParameterizedType) genericInterface;
Type[] arguments = type.getActualTypeArguments();
for (Type argument : arguments) {
System.out.println("接口泛型类型:" + argument);
}
}
}
}
// 获取方法返回值的泛型信息
public static void analyzeMethod(Method method) {
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
ParameterizedType type = (ParameterizedType) returnType;
Type[] arguments = type.getActualTypeArguments();
for (Type argument : arguments) {
System.out.println("返回值泛型类型:" + argument);
}
}
}
}
// 使用示例
public class GenericTest<T> implements List<T> {
public List<String> getList() {
return new ArrayList<>();
}
public static void main(String[] args) {
GenericReflection.analyzeGeneric(GenericTest.class);
try {
Method method = GenericTest.class.getMethod("getList");
GenericReflection.analyzeMethod(method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
七、最佳实践与常见问题
7.1 反射最佳实践
public class ReflectionBestPractices {
// 1. 缓存反射结果
private static final Map<Class<?>, Field[]> FIELDS_CACHE =
new ConcurrentHashMap<>();
public static Field[] getFields(Class<?> clazz) {
return FIELDS_CACHE.computeIfAbsent(clazz,
Class::getDeclaredFields);
}
// 2. 异常处理
public static Object invokeMethod(Object target, String methodName,
Object... args) {
try {
Class<?>[] paramTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
paramTypes[i] = args[i].getClass();
}
Method method = target.getClass()
.getDeclaredMethod(methodName, paramTypes);
method.setAccessible(true);
return method.invoke(target, args);
} catch (NoSuchMethodException e) {
throw new RuntimeException("方法不存在", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("无法访问方法", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("方法调用异常", e);
}
}
// 3. 安全检查
public static void checkAccess(Class<?> clazz) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new ReflectPermission("suppressAccessChecks"));
}
}
}
7.2 常见问题解决
public class CommonProblems {
// 1. 处理内部类
public static Class<?> getInnerClass(String outerClassName,
String innerClassName) throws ClassNotFoundException {
return Class.forName(outerClassName + "$" + innerClassName);
}
// 2. 处理数组类型
public static Class<?> getArrayClass(Class<?> componentType,
int dimensions) {
if (dimensions <= 0) {
return componentType;
}
StringBuilder classNameBuilder = new StringBuilder();
for (int i = 0; i < dimensions; i++) {
classNameBuilder.append("[");
}
if (componentType.isPrimitive()) {
classNameBuilder.append(getPrimitiveCode(componentType));
} else {
classNameBuilder.append("L")
.append(componentType.getName())
.append(";");
}
return Class.forName(classNameBuilder.toString());
}
private static String getPrimitiveCode(Class<?> primitiveType) {
if (primitiveType == boolean.class) return "Z";
if (primitiveType == byte.class) return "B";
if (primitiveType == char.class) return "C";
if (primitiveType == double.class) return "D";
if (primitiveType == float.class) return "F";
if (primitiveType == int.class) return "I";
if (primitiveType == long.class) return "J";
if (primitiveType == short.class) return "S";
throw new IllegalArgumentException("Not primitive type: " +
primitiveType);
}
// 3. 处理继承关系
public static Set<Method> getAllMethods(Class<?> clazz) {
Set<Method> methods = new LinkedHashSet<>();
while (clazz != null) {
methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
clazz = clazz.getSuperclass();
}
return methods;
}
}
7.3 面试高频考点
-
反射的优缺点?
-
优点:灵活性强,可动态操作
-
缺点:性能开销大,破坏封装性
-
应用:框架开发,插件机制
-
限制:安全性考虑,性能要求
-
-
反射与类加载的关系?
-
类加载时机
-
类加载过程
-
类加载器分类
-
双亲委派模型
-
-
如何提高反射性能?
-
缓存反射对象
-
使用setAccessible
-
批量操作优化
-
减少反射调用
-
结语
Java反射机制是框架开发的基石,掌握好反射技术对于理解主流框架的实现原理至关重要。记住:反射虽强大,但也要适度使用,在灵活性和性能之间找到平衡!
🎉 如果本文对您有帮助,请点赞收藏,您的支持是我创作的动力!
📚 下一篇我们将深入讲解Java注解机制,敬请期待!