首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 反射機制實例詳解:從入門到實戰

     編輯:Java 相關知識

反射核心類速覽

類作用
Class運行時類信息入口,獲取構造器、方法、字段、注解等
Constructor構造器信息,創建實例
Method方法信息,調用方法
Field字段信息,讀寫屬性值
Annotation注解信息,運行時讀取元數據

實戰場景一:通用對象拷貝工具

public class BeanCopier {
    public static void copy(Object source, Object target) {
        Class sourceClass = source.getClass();
        Class targetClass = target.getClass();
        
        Field[] fields = sourceClass.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                Field targetField = targetClass.getDeclaredField(field.getName());
                targetField.setAccessible(true);
                targetField.set(target, field.get(source));
            } catch (NoSuchFieldException ignored) {
                // 目標無此字段,跳過
            } catch (Exception e) {
                throw new RuntimeException("拷貝失敗: " + field.getName(), e);
            }
        }
    }
}

// 使用
UserDTO dto = new UserDTO();
UserVO vo = new UserVO();
BeanCopier.copy(dto, vo);

實戰場景二:簡易依賴注入容器

public class SimpleDIContainer {
    private final Map, Object> singletons = new ConcurrentHashMap<>();
    
    public  T getBean(Class clazz) {
        return clazz.cast(singletons.computeIfAbsent(clazz, this::createInstance));
    }
    
    private  T createInstance(Class clazz) {
        try {
            // 查找帶 @Autowired 的構造器
            Constructor[] constructors = clazz.getDeclaredConstructors();
            Constructor target = Arrays.stream(constructors)
                .filter(c -> c.isAnnotationPresent(Autowired.class))
                .findFirst()
                .orElseGet(() -> clazz.getDeclaredConstructor());
            
            target.setAccessible(true);
            Object[] args = Arrays.stream(target.getParameterTypes())
                .map(this::getBean) // 遞彡注入依賴
                .toArray();
            return clazz.cast(target.newInstance(args));
        } catch (Exception e) {
            throw new RuntimeException("創建 Bean 失敗: " + clazz, e);
        }
    }
}

實戰場景三:注解驅動的請求映射

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequestMapping {
    String value();
    RequestMethod method() default RequestMethod.GET;
}

@Controller
public class UserController {
    @RequestMapping("/users")
    public List list() { ... }
    
    @RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
    public User get(@PathVariable Long id) { ... }
}

// 掃描註冊
public class HandlerMapping {
    public Map scan(String basePackage) {
        Map mapping = new HashMap<>();
        // 掃描包下所有類...
        for (Method method : clazz.getDeclaredMethods()) {
            RequestMapping rm = method.getAnnotation(RequestMapping.class);
            if (rm != null) {
                mapping.put(rm.value(), method);
            }
        }
        return mapping;
    }
}

實戰場景四:動態代理實現 AOP

public class LoggingProxy implements InvocationHandler {
    private final Object target;
    
    public LoggingProxy(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.nanoTime();
        try {
            return method.invoke(target, args);
        } finally {
            long cost = System.nanoTime() - start;
            System.out.printf("[%s] %s 耗時: %d ms%n", 
                target.getClass().getSimpleName(), method.getName(), cost / 1_000_000);
        }
    }
    
    public static Object createProxy(Object target) {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new LoggingProxy(target)
        );
    }
}

實戰場景五:插件化/熱加載

public class PluginLoader {
    public List loadPlugins(String jarDir) {
        List plugins = new ArrayList<>();
        File dir = new File(jarDir);
        for (File jar : dir.listFiles((d, n) -> n.endsWith(".jar"))) {
            try (URLClassLoader loader = new URLClassLoader(new URL[]{jar.toURI().toURL()})) {
                ServiceLoader loader = ServiceLoader.load(Plugin.class, loader);
                for (Plugin plugin : loader) {
                    plugins.add(plugin);
                }
            }
        }
        return plugins;
    }
}

性能優化關鍵點

  • 緩存 Class/Method/Field 對象:反射對象創建開銷大,靜態緩存復用
  • setAccessible(true) 一次性設置:避免重複安全檢查
  • MethodHandle/VarHandle (Java 7/9+):比反射快 10-100x,JIT 友好
  • 避免熱路徑使用反射:高頻調用路徑改用代碼生成 (ASM/ByteBuddy) 或 MethodHandle

安全風險與防範

  • 反射可破壞封裝、單例、不可變對象
  • SecurityManager 可限制 suppressAccessChecks 權限
  • 模塊化 (Java 9+) 需 opens package to module 才能深度反射

反射是框架開發的基石 (Spring、Hibernate、MyBatis 等),業務代碼慎用,工具類/框架代碼善用。掌握上述 5 大實戰場景,覆蓋 90% 反射應用需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved