Java中的动态类型转换

3

在我开始之前,我想说明一下:我已经尽力去寻找与Java泛型和动态类型转换相关的问题线索了。如果我有所疏漏,敬请谅解。

类型Scalar的定义如下:

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;
}

当然,这通常是不被鼓励的。我需要这样一个方法的原因是,我有一组标量的值,我希望稍后更改它们。然而,一旦它们进入集合中,它们的泛型类型参数就不再可访问。因此,即使我想要进行在运行时完全有效的赋值,也无法知道它是否在编译时有效,无论是否使用泛型。

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异常吗?


也许你可以完全省略泛型?为什么不直接使用Number代替T呢? - Skip Head
在我沮丧的时候,我很想这样做,但是我想为一个具有单位感知能力的 RichScalar 留下这个设施。 - dgorur
1个回答

3

你拥有:

this.value.getClass().isAssignableFrom(val.getClass())

如果您不能确定value永远不会为空,那么这可能会成为一个问题。

您还有:

this.value = (T) val;

这将只转换为Number,而不是T,因为在底层由于类型擦除,T只是一个Number。因此,如果valueDouble,而valInteger,则不会抛出异常。
如果你实际上想执行一个检查过的转换,你必须拥有正确的Class<T>对象。这意味着你应该在对象的构造函数中传递Class<T>。(除非你能确定value永远不会为空,在这种情况下,你可以选择第一个想法。)一旦你拥有了那个对象(存储在一个字段中),你就可以执行检查过的转换:
T value = valueClass.cast(val);

谢谢您的回复!我可以轻松地检查空值。但是假设我使用了我的第一个解决方案,那么我接下来该怎么办呢?在我的原始代码片段中,强制转换语法会引发编译错误,并且使用(T)val进行转换仍然会有未经检查的转换警告,这意味着isAssignable(...)测试并没有真正被使用。 - dgorur
1
@dgorur,你原始代码片段中的转换并没有指定。你只是写了“// Some cast code here”。应该是:value = value.getClass().cast(val);,这样可以编译通过。 - Kirk Woll
我将转换代码放在了代码片段的底部,但它却无法编译通过。有趣的是,它却可以在你那里编译通过!可能是javac版本或其他原因吗?Eclipse告诉我:类型不匹配:无法从capture#1-of ? extends Number转换为T。这就是我在代码片段中提供原因的方式... - dgorur
CastAway.java:16: 不兼容的类型 找到:? extends java.lang.Number 的 capture#556 需要:T value = value.getClass().cast(val); ^ 1 错误 - dgorur
$ javac -version javac 1.6.0_20 - dgorur
@dgorur,你是对的,我的示例中有一个错误,我忘记了getClass()返回的是Class<?>而不是Class<T>。你需要将Class<T>(valueClass)传递到你的类的构造函数中。 - Kirk Woll

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接