gpt4 book ai didi

java - 确保通用 lambda 表达式的类型安全

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:08:21 25 4
gpt4 key购买 nike

这是对 Java8 retrieving lambda setter from class 的跟进.

我正在尝试获取给定字段的 getter 方法

public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Field field) {

Class<R> fieldType = null;
try {
fieldType = (Class<R>) field.getType();
} catch(ClassCastException e) {
error("Attempted to create a mistyped getter for the field " + field + "!");
}

return getGetter(clazz, field.getName(), fieldType);
}

这是底层方法:

public <T, R> IGetter<T, R> getGetter(Class<T> clazz, String fieldName, Class<R> fieldType) {

MethodHandles.Lookup caller = null;
MethodHandle target = null;
MethodType func = null;

try {
caller = MethodHandles.lookup();
MethodType getter = MethodType.methodType(fieldType);
target = caller.findVirtual(clazz, computeGetterName(fieldName), getter);
func = target.type();
} catch (NoSuchMethodException e) {
error("Could not locate a properly named getter \"" + computeGetterName(fieldName) + "\"!");
} catch (IllegalAccessException e) {
error("Could not access \"" + computeGetterName(fieldName) + "\"!");
}

CallSite site = null;
try {
site = LambdaMetafactory.metafactory(
caller,
"get",
MethodType.methodType(IGetter.class),
func.generic(),
target,
func
);
} catch (LambdaConversionException e) {
error("Could not convert the getter \"" + computeGetterName(fieldName) + "\" into a lambda expression!");
}

MethodHandle factory = site.getTarget();

IGetter<T, R> r = null;
try {
r = (IGetter<T, R>) factory.invoke();
} catch (Throwable throwable) {
error("Casting the factory of \"" + computeGetterName(fieldName) + "\" failed!");
}

return r;
}

由于类型不匹配,无法编译:

IGetter<TestEntity, Long> getter = accessorFactory.getGetter(TestEntity.class, "name", String.class);

然而,这确实编译:

Field field = TestEntity.class.getDeclaredField("name");
IGetter<TestEntity, Long> getter = accessorFactory.getGetter(TestEntity.class, field);

而且,令我惊讶的是,这确实可以使用上面检索到的 getter:

TestEntity testEntity = new TestEntity(1L, "Test");
System.out.println(getter.get(testEntity));

但是,一旦我这样做:

Long value = getter.get(testEntity);

我得到以下异常:

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
at de.cyclonit.exercise.Main.main(Main.java:26)

有什么方法可以更早地捕捉到它吗?

测试实体类:

public class TestEntity {

private Long id;

private String name;


public TestEntity(Long id, String name) {
this.id = id;
this.name = name;
}


public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}
}

最佳答案

问题是你的方法

public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Field field) {
Class<R> fieldType = null;
try {
fieldType = (Class<R>) field.getType();
} catch(ClassCastException e) {
error("Attempted to create a mistyped getter for the field " + field + "!");
}
return getGetter(clazz, field.getName(), fieldType);
}

实际上并没有执行检查。你基本上是在转换 Class要键入的实例 Class这没有效果。泛型的变化Class<?>Class<R>是纯编译时的事情,这就是为什么此时您应该收到“未检查”警告的原因,至少,如果启用了所有警告。

在运行时进行真正检查的唯一方法是从调用者那里获取预期的类型:

public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Class<R> fieldType, Field field) {
if(fieldType != field.getType()) {
error("Attempted to create a mistyped getter for the field " + field + "!");
}
return getGetter(clazz, field.getName(), fieldType);
}

当然,它使方法接受 Field有点无意义。实际getGetter将已经执行查找,要求与 getter 的返回类型完全匹配,而要求字段类型和 getter 的返回类型必须匹配对您没有任何好处。实际上,它对内部细节造成了不必要的依赖。

为什么不简单地注释 getter 而不是字段......

关于java - 确保通用 lambda 表达式的类型安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43985636/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com