反射是 Java 動態性的核心,支撐著 Spring、Hibernate、MyBatis 等主流框架。本文系統講解反射三大核心能力:類結構探測、註解元數據處理、泛型類型擷取,並給出生產級代碼範例。
// 1. 類字面量 (編譯期已知)
Class<User> clazz = User.class;
// 2. 實例 getClass() (運行期對象)
User user = new User();
Class<?> clazz2 = user.getClass();
// 3. 字符串全限定名 (配置驅動)
Class<?> clazz3 = Class.forName("com.example.User");
System.out.println("完整類名: " + clazz.getName()); // com.example.User
System.out.println("簡單類名: " + clazz.getSimpleName()); // User
System.out.println("規範名: " + clazz.getCanonicalName()); // com.example.User
// 所有聲明字段 (含 private,不含繼承)
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f.getModifiers() + " " + f.getType().getSimpleName() + " " + f.getName());
// private String name
// private int age
// private String sex
}
// 僅 public 字段 (含繼承)
Field[] publicFields = clazz.getFields();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m.getName() + " -> " + m.getReturnType().getSimpleName()
+ " " + Arrays.toString(m.getParameterTypes()));
}
// 精確獲取帶參方法
Method setSex = clazz.getDeclaredMethod("setSex", String.class);
Constructor<?>[] constructors = clazz.getConstructors(); // 僅 public
for (Constructor<?> c : constructors) {
System.out.println(c.getParameterCount() + " 參數: " + Arrays.toString(c.getParameterTypes()));
}
// 0 參數: []
// 3 參數: [String, int, String]
// 無參構造器
User u1 = clazz.getDeclaredConstructor().newInstance();
// 帶參構造器
Constructor<User> ctor = clazz.getDeclaredConstructor(String.class, int.class, String.class);
User u2 = ctor.newInstance("Alice", 25, "Female");
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value() default "";
String schema() default "public";
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String name() default "";
String type() default "varchar";
int length() default 255;
boolean nullable() default true;
boolean primaryKey() default false;
}
public class DdlGenerator {
public static String generateCreateTable(Class<?> entityClass) {
Table tableAnn = entityClass.getAnnotation(Table.class);
String tableName = tableAnn != null && !tableAnn.value().isEmpty()
? tableAnn.value() : entityClass.getSimpleName().toLowerCase();
StringBuilder sql = new StringBuilder("CREATE TABLE ").append(tableName).append(" (\n");
Field[] fields = entityClass.getDeclaredFields();
List pkColumns = new ArrayList<>();
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
Column colAnn = f.getAnnotation(Column.class);
if (colAnn == null) continue; // 忽略無註解字段
String colName = colAnn.name().isEmpty() ? f.getName() : colAnn.name();
String colType = colAnn.type();
if (colAnn.length() > 0 && !colType.contains("(")) {
colType += "(" + colAnn.length() + ")";
}
String nullable = colAnn.nullable() ? "" : " NOT NULL";
sql.append(" ").append(colName).append(" ").append(colType).append(nullable);
if (i < fields.length - 1) sql.append(",");
sql.append("\n");
if (colAnn.primaryKey()) pkColumns.add(colName);
}
if (!pkColumns.isEmpty()) {
sql.append(" PRIMARY KEY (").append(String.join(", ", pkColumns)).append(")\n");
}
sql.append(");");
return sql.toString();
}
}
// 輸出:
// CREATE TABLE t_user (
// id bigint NOT NULL,
// username varchar(50),
// age int
// PRIMARY KEY (id)
// );
public class GenericDao<T> {
private Class<T> entityClass;
// 錯誤: 運行期 T 擦除為 Object
// public GenericDao() { this.entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; }
// 正確: 子類指定具體類型時保留泛型信息
public GenericDao(Class<T> entityClass) { this.entityClass = entityClass; }
}
public abstract class TypeToken<T> {
private final Type type;
protected TypeToken() {
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof ParameterizedType) {
this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
} else {
throw new IllegalStateException("必須在匿名內部類中指定具體類型");
}
}
public Type getType() { return type; }
public Class<?> getRawType() {
return (type instanceof Class) ? (Class<?>) type : (Class<?>) ((ParameterizedType) type).getRawType();
}
}
// 使用:
TypeToken token = new TypeToken<List<String>>() {};
System.out.println(token.getType()); // java.util.List
System.out.println(token.getRawType()); // interface java.util.List
public class MethodGenericResolver {
public static void main(String[] args) throws NoSuchMethodException {
Method m1 = MethodGenericResolver.class.getDeclaredMethod("process", Map.class, List.class);
Method m2 = MethodGenericResolver.class.getDeclaredMethod("result");
// 參數泛型
Type[] paramTypes = m1.getGenericParameterTypes();
for (Type pt : paramTypes) {
if (pt instanceof ParameterizedType) {
ParameterizedType ppt = (ParameterizedType) pt;
System.out.println("原始類型: " + ppt.getRawType());
System.out.println("實際類型參數: " + Arrays.toString(ppt.getActualTypeArguments()));
}
}
// 輸出:
// 原始類型: interface java.util.Map
// 實際類型參數: [class java.lang.String, class java.lang.String]
// 原始類型: interface java.util.List
// 實際類型參數: [class java.lang.Integer]
// 返回值泛型
Type returnType = m2.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
ParameterizedType prt = (ParameterizedType) returnType;
System.out.println("返回: " + prt.getRawType() + "<" + Arrays.toString(prt.getActualTypeArguments()) + ">");
}
// 輸出: 返回: interface java.util.Map<[class java.lang.String, class java.lang.String]>
}
public void process(Map<String, String> map, List<Integer> list) {}
public Map<String, String> result() { return null; }
}
| 維度 | JDK Proxy | CGLIB |
|---|---|---|
| 前提條件 | 目標實現接口 | 無需接口,繼承類 |
| 核心機制 | 接口實現類生成 | 字節碼生成子類 |
| 關鍵類 | Proxy, InvocationHandler | Enhancer, MethodInterceptor |
| final 方法 | 可代理 | 無法攔截 |
| 性能 | 調用略慢 (反射) | FastClass 機制較快 |
public class JdkProxyFactory {
public static <T> T createProxy(T target, InvocationHandler handler) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
}
}
// 使用:
UserDao target = new UserDaoImpl();
UserDao proxy = JdkProxyFactory.createProxy(target, (proxyObj, method, args) -> {
System.out.println("Before: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After: " + method.getName());
return result;
});
public class CglibProxyFactory {
public static <T> T createProxy(Class<T> targetClass, MethodInterceptor interceptor) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(interceptor);
return (T) enhancer.create();
}
}
// 使用 (目標類無需接口):
UserService target = new UserServiceImpl();
UserService proxy = CglibProxyFactory.createProxy(UserService.class, (obj, method, args, proxy) -> {
if (method.getName().startsWith("save")) {
TransactionManager.begin();
}
try {
Object result = proxy.invokeSuper(obj, args);
if (method.getName().startsWith("save")) TransactionManager.commit();
return result;
} catch (Exception e) {
if (method.getName().startsWith("save")) TransactionManager.rollback();
throw e;
}
});
--add-opens反射三大核心價值:運行期類結構探測、註解驅動元編程、泛型類型擷取突破擦除。掌握 Class/Field/Method/Constructor/Type 體系,配合 TypeToken 模式解決泛型擦除,善用 JDK Proxy/CGLIB 實現 AOP 橫切關注點,是框架開發與高級應用開發的必備技能。