在我不做功课之前,我一直无法找到关于Java泛型和动态投射的众多问题的任何线索。
标量类型定义如下:
public class Scalar <T extends Number> {
public final String name;
T value;
...
public T getValue() {
return value;
}
public void setValue(T val) {
this.value = val;
}
}
我想有一个看起来像这样的方法:
public void evilSetter(V val) {
this.value = (T) val;
}
当然,这通常是气馁的。我想要这样一个方法的原因是因为我有一组Scalars,我想稍后更改它们的值。但是,一旦进入集合,就无法再访问其泛型类型参数。因此,即使我想在运行时创建一个完全有效的赋值,也无法知道它在编译时是否有效,无论是否有泛型。
Map<String, Scalar<? extends Number>> scalars = ...;
Scalar<? extends Number> scalar = scalars.get("someId");
// None of this can work
scalar.value = ...
scalar.setValue(...)
那么我该如何实现一个经过检查的强制转换和设置方法呢?
public <V extends Number> void castAndSet(V val) {
// One possibility
if (this.value.getClass().isAssignableFrom(val.getClass()) {
// Some cast code here
}
// Another
if (this.value.getClass().isInstanceOf(val) {
// Some cast code here
}
// What should the cast line be?
// It can't be:
this.value = this.value.getClass().cast(val);
// Because this.value.getClass() is of type Class<?>, not Class<T>
}
所以我离开了
this.value = (T) val;
并捕获ClassCastException?
答案 0 :(得分:3)
你有:
this.value.getClass().isAssignableFrom(val.getClass())
除非您确定value
永远不会为空,否则这可能会成为一个问题。
您还有:
this.value = (T) val;
这只会转发到Number
而不是T
,因为由于类型删除,引擎T
只是Number
。因此,如果value
是Double
且val
是Integer
,则不会抛出异常。
如果您确实想要执行已检查广告投放,则必须拥有正确的Class<T>
对象。这意味着您应该在对象的构造函数中传递Class<T>
。 (除非你可以确定value
永远不会为空,在这种情况下你可以按照你的第一个想法。)一旦你有了这个对象(存储在一个字段中),你就可以执行检查的强制转换:
T value = valueClass.cast(val);