元素战纪手游
74.02MB · 2025-12-15
适用人群:想快速上手/查阅反射写法的 Java 工程师。 运行环境:建议 JDK 11+,最佳 JDK 17/21。 关键词:Class、Field、Method、Constructor、MethodHandle、VarHandle、Proxy、Type。
Class 的三种方式Class.newInstance())FieldMethodConstructorType 家族--add-opens/opens)ProxyClass 的三种方式Class<?> c1 = String.class; // 字面量
Class<?> c2 = "Hello".getClass(); // 实例 -> Class
Class<?> c3 = Class.forName("java.lang.String"); // 全限定名加载
小贴士:基本类型与数组也有 Class:int.class、String[].class。
Class.newInstance())不要再用clazz.newInstance()(JDK 9+ 已弃用)。 推荐使用无参构造器的标准替代:
MyType obj = MyType.class.getDeclaredConstructor().newInstance();
Constructor<MyType> ctor = MyType.class.getDeclaredConstructor(String.class, int.class);
ctor.setAccessible(true); // 若非 public
MyType obj = ctor.newInstance("Ocean", 42);
说明:getDeclaredConstructor 能拿到非 public 构造;遇到访问限制需结合模块化策略(见 §9)。
FieldField f = MyType.class.getDeclaredField("name"); // 含私有
f.setAccessible(true); // 破私有(受模块限制)
f.set(obj, "Ocean");
Object val = f.get(obj);
for (Field fd : MyType.class.getDeclaredFields()) {
fd.setAccessible(true);
System.out.println(fd.getName() + " : " + fd.getType());
}
MethodMethod m = MyType.class.getDeclaredMethod("sayHello", String.class);
m.setAccessible(true);
Object ret = m.invoke(obj, "World");
for (Method pm : MyType.class.getMethods()) {
System.out.println(pm);
}
ConstructorConstructor<MyType> ctor = MyType.class.getDeclaredConstructor();
ctor.setAccessible(true);
MyType instance = ctor.newInstance();
for (Constructor<?> c : MyType.class.getDeclaredConstructors()) {
System.out.println(c);
}
// 类、字段、方法上的注解
MyAnno anno = MyType.class.getAnnotation(MyAnno.class);
// 方法参数名(需编译参数 -parameters)
Method m = MyType.class.getDeclaredMethod("foo", String.class, int.class);
for (Parameter p : m.getParameters()) {
System.out.println(p.getName() + " : " + p.getType());
}
Type 家族Field f = Repo.class.getDeclaredField("data"); // e.g. Map<String, List<User>>
Type t = f.getGenericType();
if (t instanceof ParameterizedType pt) {
Type raw = pt.getRawType(); // Map
Type[] args = pt.getActualTypeArguments(); // [String, List<User>]
}
Type 子接口:
Class<?>:普通类型ParameterizedType:带泛型参数的类型,如 List<String>TypeVariable:类型变量,如 TWildcardType:通配符,如 ? extends NumberGenericArrayType:泛型数组,如 T[]--add-opens/opens)setAccessible(true)),会抛 IllegalAccessException 或非法反射访问警告/失败。java --add-opens my.module/com.example.internal=ALL-UNNAMED -jar app.jar
2. **模块描述符中显式开放**(长期方案)
// module-info.java
open module my.module {
// 或者有选择地 opens 某些包
// opens com.example.internal to other.module;
}
Proxyinterface Hello { String hi(String name); }
InvocationHandler h = (proxy, method, args) -> {
if (method.getName().equals("hi")) {
return "[LOG] " + args[0];
}
return method.invoke(proxy, args);
};
Hello hello = (Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(),
new Class<?>[]{Hello.class},
h
);
System.out.println(hello.hi("Ocean")); // [LOG] Ocean
如果需要代理类(非接口),可使用 ByteBuddy、CGLIB、Javassist 等字节码库。
**MethodHandle**:更接近直接调用的可链接句柄,类型安全,常比 Method.invoke 更快。MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(MyType.class, "sayHello",
MethodType.methodType(String.class, String.class));
String r = (String) mh.invoke(obj, "World");
**VarHandle**(JDK 9+):字段/数组/字节缓冲区的“变量句柄”,支持原子/内存栅栏等操作:VarHandle NAME;
static {
try {
NAME = MethodHandles.lookup()
.in(MyType.class)
.findVarHandle(MyType.class, "name", String.class);
} catch (Exception e) { throw new RuntimeException(e); }
}
NAME.set(obj, "Ocean");
String v = (String) NAME.get(obj);
一般规则:频繁调用/性能敏感 → 优先考虑 MethodHandle/VarHandle;一次性工具/低频 → 传统反射 API 足够。
Field/Method/Constructor 查找与 setAccessible 代价不小,建议按类型做缓存。MethodHandle 并缓存句柄。ClassNotFoundException:类名或类路径错误。NoSuchMethodException / NoSuchFieldException:签名或名称不匹配(包含参数类型/顺序)。IllegalAccessException:访问权限/模块未 opens。InvocationTargetException:被调用方法抛出的异常被包装在此处。InaccessibleObjectException(JDK 16+ 常见):模块强封装导致;用 --add-opens 或 opens 解决。public static <T> T newInstance(Class<T> type) {
try {
Constructor<T> c = type.getDeclaredConstructor();
c.setAccessible(true);
return c.newInstance();
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Cannot instantiate: " + type.getName(), e);
}
}
public static Object readField(Object target, String name) {
try {
Field f = target.getClass().getDeclaredField(name);
f.setAccessible(true); // 若报 InaccessibleObjectException,参见 §9
return f.get(target);
} catch (ReflectiveOperationException e) {
throw new IllegalStateException(e);
}
}
for (Method m : clazz.getDeclaredMethods()) {
m.setAccessible(true);
System.out.println(m.getName());
for (Annotation a : m.getAnnotations()) {
System.out.println(" @" + a.annotationType().getSimpleName());
}
}
public static List<Class<?>> genericArgsOfField(Field f) {
Type t = f.getGenericType();
if (t instanceof ParameterizedType pt) {
List<Class<?>> list = new ArrayList<>();
for (Type arg : pt.getActualTypeArguments()) {
if (arg instanceof Class<?> cls) list.add(cls);
// 可扩展处理 WildcardType/TypeVariable 等
}
return list;
}
return List.of();
}
MethodHandlefinal class Handles {
private static final Map<String, MethodHandle> CACHE = new ConcurrentHashMap<>();
static MethodHandle vh(Class<?> c, String name, Class<?> ret, Class<?>... params) {
return CACHE.computeIfAbsent(c.getName() + "#" + name, k -> {
try {
return MethodHandles.lookup().findVirtual(c, name, MethodType.methodType(ret, params));
} catch (Throwable e) { throw new RuntimeException(e); }
});
}
}
getDeclaredConstructor().newInstance() 取代 Class.newInstance()。--add-opens 或在 module-info.java 中 opens。MethodHandle/VarHandle,并缓存句柄/成员。ReflectiveOperationException 分支,封装为业务异常。