【问题标题】:abstract type T is unchecked since it is eliminated by erasure抽象类型 T 未检查,因为它已被擦除消除
【发布时间】:2016-08-05 21:29:10
【问题描述】:

我正在编写一个扩展 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]
  }

我该如何实现这个方法?

【问题讨论】:

  • 也许这会有所帮助:http://stackoverflow.com/questions/1094173.
  • 由于擦除将第二个“if”语句转换为“isInstanceOf[Object]”,这始终是正确的,这实际上保证不会按照程序员的意图进行。我很震惊,这是一个警告而不是错误。我意识到这个问题不能以类型安全的方式解决,因为输入是 Any,输出是 T。我从 Alexey 的解决方案中意识到,一旦你开始做这样的事情,你基本上是在告诉编译器“信任我,在运行时这将被强制转换为 T”,编译器的“类型安全保证”变为“我看到程序员承诺了一个 T”。

标签: scala inheritance erasure


【解决方案1】:

您的 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]
}

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

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

作为旁注,虽然您可以摆脱警告,但具有这样签名的方法的存在强烈表明作者对 Java 泛型的理解不够好,我会非常小心依赖那个库。

【讨论】:

    【解决方案2】:

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

    1. 用Java实现:

      @SuppressWarnings("未选中") @Override 公共T执行(对象值){ if (value == null || "None".equals(String.valueOf(value))) 返回 null; 否则返回(T)值; }

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

      def 执行[T](值:任意):T = { if (value == null || value == "None") null.asInstanceOf[T] else if (value.isInstanceOf[T @unchecked]) value.asInstanceOf[T] 否则 null.asInstanceOf[T] }

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

    感谢 Alec 的建议!

    【讨论】:

    • 这是否符合您的要求?你所做的只是抑制警告......
    • 擦除仍然会得到你。如果您无法添加ClassTagManifest,您可能是SOL,必须使用Java 实现。
    • 如果我查看 Java 代码,我确信它可以满足我的需求,因为我了解它的功能。几乎没有一个实现依赖于 T。最后的演员表可以忽略,我仍然得到我想要的。在 Scala 中,我不明白擦除后的第二个 if 语句是什么。我得测试一下。
    • 因为我已经删除了我的答案(因为它不起作用,因为 OP 无法添加 ClassTagManifest)这里是,供将来参考def execute[T : ClassTag](value: Any): T = value match { case "None" => null.asInstanceOf[T] case x: T => x case _ => null.asInstanceOf[T] }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-12
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多