【问题标题】:Dynamic casting in JavaJava中的动态转换
【发布时间】:2010-10-15 02:27:19
【问题描述】:

在我因为没有做功课而受到责备之前,我一直无法找到有关 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?
  • 在我的挫折中,我很想这样做,但我想离开这个设施,例如,一个单位感知的 RichScalar。

标签: java dynamic generics casting


【解决方案1】:

你有:

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

这可能会成为一个问题,除非您可以确定 value 永远不会为空。

你还有:

this.value = (T) val;

这只会转换为Number 而不会转换为T,因为在底层T 由于类型擦除而只是Number。因此,如果valueDouble 并且valInteger,则不会抛出异常。

如果您确实想要执行 checked 强制转换,您必须拥有正确的 Class&lt;T&gt; 对象。这意味着您应该在对象的构造函数中传递Class&lt;T&gt;。 (除非您可以确定 value 永远不会为空,在这种情况下,您可以采用您的第一个想法。)一旦您拥有该对象(存储在字段中),您就可以执行检查转换:

T value = valueClass.cast(val);

【讨论】:

  • 感谢您的回复!我可以很容易地检查空值。但是假设我确实使用了我的第一个解决方案,那么我该从哪里开始呢?我的原始代码 sn-p 中的强制转换语法会引发编译错误,并且使用 (T) val 进行强制转换仍然有未经检查的转换警告,这意味着 isAssignable(...) 测试并没有真正被使用。
  • @dgorur,未指定原始代码 sn-p 的演员表。你只有“//这里有一些演员代码”。它应该是:value = value.getClass().cast(val);,它会编译。
  • 我将强制转换代码放在代码 sn-p 的底部,以及它无法为我编译的原因。有趣的是它确实为你编译!会不会是 javac 版本之类的? Eclipse 告诉我:类型不匹配:无法从 capture#1-of 转换?将 Number 扩展到 T。这就是我在代码中提供的原因 sn-p...
  • CastAway.java:16: 发现不兼容的类型: capture#556 of ?扩展 java.lang.Number 要求:T value = value.getClass().cast(val); ^ 1 个错误
  • $ javac -version javac 1.6.0_20
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-07
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
相关资源
最近更新 更多