抽象类型T是未选中的,因为它是通过擦除来消除的

时间:2016-08-05 21:29:11

标签: scala inheritance erasure

我正在编写一个扩展Java类的Scala类。我必须扩展这个抽象的Java类,因为它包含一些转换器,我需要编写一个我可以插入其框架的转换器。因此,下面的方法的签名被强加给我:当我说我的类扩展他们的抽象类时,Eclipse会自动生成它。如果我尝试修改方法签名,则该类无法编译,因为“它没有从父级实现抽象方法”。

方法的实现当然是我的选择 - 但我发现我无法满足类型系统的约束。

我需要做一些非常简单的事情:将“None”视为null并返回其他任何内容。但我发现我不能以类型安全的方式做到这一点。如果我编写如下所示的代码,我会收到一条警告,说“抽象类型T未经检查,因为它被擦除”。我怎样才能消除这种情况?

我也想知道如果应用到我的代码,一旦擦除,我的代码会是什么样的,即第二个“if”条件看起来像什么。

直观地说,我理解当输入为Any时我无法保证返回T - 这就是编译器不满意的原因。在实践中,这将起作用,因为我们只是读取字符串并返回字符串 - 但是继承声明强制了方法签名。

  def execute[T](value: Any): T = {
    if (value == null || value == "None") null.asInstanceOf[T]
    // Warning: abstract type T is unchecked since it is eliminated by erasure
    else if (value.isInstanceOf[T]) value.asInstanceOf[T]
    //            warning here: ^
    else null.asInstanceOf[T]
  }

如何实施此方法?

2 个答案:

答案 0 :(得分:2)

您的Java解决方案不包含测试value instanceof T,因此您在Scala解决方案中不需要isInstanceOf[T]。你应该删除它,因为检查没有做任何事情:它会删除到isInstanceOf[Object],这总是正确的,所以从不采用最后一个else分支。剩下的区别是,在Java中,您将String.valueOf(value)"None"进行比较,而不是value本身。所以Java解决方案的等价物是

def execute[T](value: Any): T = {
  (if (value == null || String.valueOf(value) == "None") null else value).asInstanceOf[T]
}

根据value == null || value.toString == "None"的定义,条件可以简化为String.valueOf

IMO,编译器应该对asInstanceOf[T]发出警告,而不仅仅是isInstanceOf[T];这是一个Java实际上比Scala更安全的情况,因为1)它确实给出了强制转换的警告; 2)instanceof检查将是错误而不是警告。

作为旁注,当你可以摆脱警告时,带有这样的签名的方法的存在强烈地表明作者不能很好地理解Java泛型并且我将是非常小心依赖那个图书​​馆。

答案 1 :(得分:1)

最后,我可以做以下两件事之一:

  1. 在Java中实现:

    @SuppressWarnings( “未登记”) @覆盖 public T execute(Object value){     if(value == null ||“None”.equals(String.valueOf(value)))返回null;     否则返回(T)值; }

  2. 在Scala中实现并添加@unchecked

    def execute [T](值:任意):T = {     if(value == null || value ==“None”)null.asInstanceOf [T]     else if(value.isInstanceOf [T @unchecked])value.asInstanceOf [T]     else null.asInstanceOf [T] }

  3. 我仍然想知道擦除后第二个if语句还剩下什么。

    感谢Alec的建议!