wol*_*m77 4 java reflection java-8
考虑weightclass 中的一个字段Animal。我希望能够创建用于操作此字段的getter和setter功能接口对象。
class Animal {
int weight;
}
Run Code Online (Sandbox Code Playgroud)
我目前的方法类似于用于方法的方法:
public static Supplier getter(Object obj, Class<?> cls, Field f) throws Exception {
boolean isstatic = Modifier.isStatic(f.getModifiers());
MethodType sSig = MethodType.methodType(f.getType());
Class<?> dCls = Supplier.class;
MethodType dSig = MethodType.methodType(Object.class);
String dMthd = "get";
MethodType dType = isstatic? MethodType.methodType(dCls) : MethodType.methodType(dCls, cls);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle fctry = LambdaMetafactory.metafactory(lookup, dMthd, dType, dSig, lookup.unreflectGetter(f), sSig).getTarget();
fctry = !isstatic && obj!=null? fctry.bindTo(obj) : fctry;
return (Supplier)fctry.invoke();
}
Run Code Online (Sandbox Code Playgroud)
但这会产生以下错误:
java.lang.invoke.LambdaConversionException: Unsupported MethodHandle kind: getField x.Animal.weight:()int
Run Code Online (Sandbox Code Playgroud)
更新
我试图创建一个类ObjectMap实现interface Map,基本上试图表现的对象为Map,其中对象可以是任何类型的。目前正在使用Field.get()和Field.set()操作get()和put()方法中的字段,并使用上述方法来创建Supplier和Consumer调用getter和setter方法的对象。我想知道是否可以将两种不同的方法合二为一。
可以用作Mapthrough 的示例类ObjectMap:
public class ThisCanBeAnything {
/* fields */
public String normalField;
private int hiddenFiled;
private String hiddenReadonlyField;
/* getters and setters */
public int hiddenField() {
return hiddenField;
}
public void hiddenField(int v) {
System.out.println("set: hiddenField="+v);
hiddenField = v;
}
public String hiddenReadonlyField() {
return hiddenReadonlyField;
}
}
Run Code Online (Sandbox Code Playgroud)
这是预期的用法:
Object o = new ThisCanBeAnything();
Map m = new ObjectMap(o);
m.put("normalField", "Normal");
System.out.println(m.get("normalField")); // Normal
m.put("hiddenField", 1); // set: hiddenField=1
System.out.println(m.get("hiddenField")); // 1
m.put("hiddenReadonlyField", 1); // does not do anything
System.out.println(m.get("hiddenReadonlyField")); // null
Run Code Online (Sandbox Code Playgroud)
你让它变得太困难了。当你有一个 时Field,你可以直接调用unreflectGetter查找工厂来检索一个MethodHandle:
生成一个方法句柄,提供对反射字段的读取访问权限。方法句柄的类型将具有字段值类型的返回类型。如果该字段是静态的,则方法句柄将不带任何参数。否则,它的单个参数将是包含该字段的实例。
public static Supplier<Object> getter(Object obj, Class<?> cls, Field f) {
f.setAccessible(true);
MethodHandles.Lookup lookup = MethodHandles.lookup();
return () -> {
try {
MethodHandle handle = lookup.unreflectGetter(f);
return Modifier.isStatic(f.getModifiers()) ? handle.invoke() : handle.invoke(obj);
} catch (Throwable t) {
throw new IllegalArgumentException(t);
}
};
}
Run Code Online (Sandbox Code Playgroud)
这将返回字段值的供应商。根据字段的可访问性,您可能需要调用setAccessible(true).
请注意,方法句柄和反射 API在性能方面也有所不同,可能会更快。
函数式风格让你以新的方式思考这些事情。而不是基于反射的方法,例如
Supplier getter(Object obj, Class<?> cls, Field f){...}
Run Code Online (Sandbox Code Playgroud)
尝试类似的东西
static <O,F> Supplier<F> getter(O obj, Function<O,F> extractor) {
return () -> extractor.apply(obj);
}
Run Code Online (Sandbox Code Playgroud)
你会像这样调用
Supplier<Integer> getWeight = getter(animal, a -> a.weight);
Integer weight = getWeight.get();
Run Code Online (Sandbox Code Playgroud)
a -> a.weight还有比想出一个过孔反射更难的吗Field?
一个优点是您可以根据需要使用字段或方法,例如,如果您添加了权重吸气剂,
Supplier<Integer> getWeight = getter(animal, Animal::getWeight);
Run Code Online (Sandbox Code Playgroud)
类似的 setter 工厂可能是
static <O,F> Consumer<F> setter(O obj, BiConsumer<O,F> modifier) {
return field -> modifier.accept(obj,field);
}
Run Code Online (Sandbox Code Playgroud)
像这样调用
Consumer<Integer> setWeight = setter(animal, (a, w) -> a.weight = w);
setWeight.accept(90);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5372 次 |
| 最近记录: |