java - 无法在泛型类中将 Double 转换为 Float

标签 java scala

尝试在 Scala 中使用泛型类型时遇到了困难。 这是我的代码片段。

 import scala.reflect.ClassTag

 class test[A:ClassTag] {
  private val arr: Array[A] = Array.tabulate(10){ x=>
    ((1.0 + x) / 5.0).asInstanceOf[A]
  }

  def apply(i: Int): A = arr(i)
}

val obj = new test[Float]
println(obj(1))

这段代码会抛出一个错误

java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Float
    at scala.runtime.BoxesRunTime.unboxToFloat(scratch_1.scala:105)
    at scala.collection.mutable.ArrayBuilder$ofFloat.$plus$eq(scratch_1.scala:460)
    at scala.Array$.tabulate(scratch_1.scala:327)
    at #worksheet#.test.<init>(scratch_1.scala:4)
    at #worksheet#.obj$lzycompute(scratch_1.scala:11)
    at #worksheet#.obj(scratch_1.scala:11)
    at #worksheet#.#worksheet#(scratch_1.scala:11)

当 A = Double 类型时,代码会给出 Double 类型的输出。

但是当 A = Float 类型时,就会抛出这个错误。

此处的任何反馈都非常有用。

最佳答案

您可以通过将 @specialized(Float) 添加到 A: ClassTag 类型参数来解决此问题。

这是您的代码的稍微简化的版本,其中添加了 @specialized(Float) 标记。 (我还添加了 @specialized(Int) 以使示例更加完整。)

import scala.reflect.ClassTag

class Test[@specialized(Float, Int) A: ClassTag] {
  def apply(count: Int): Array[A] = Array.tabulate(count) { 
    i => (1.5 + i).asInstanceOf[A];
  }
}

val floatTest = new Test[Float];
println(floatTest(5).mkString(", ")); // 1.5, 2.5, 3.5, 4.5, 5.5
// Works because code is specialized for float
// and primitive double is cast to primitive float.

val doubleTest = new Test[Double];
println(doubleTest(5).mkString(", ")); // 1.5, 2.5, 3.5, 4.5, 5.5
// Works although code is not specialized for double
// but Double object can be cast to Double object.

val intTest = new Test[Int];
println(intTest(5).mkString(", ")); // 1, 2, 3, 4, 5
// Works because code is specialized for int
// and primitive double is cast to primitive int.

val longTest = new Test[Long];
println(longTest(5).mkString(", ")); // ClassCastException
// Fails because code is not specialized for long
// and Double object cannot be cast to Long object.
// Works if you add @specialized(Long).

(从 Double 对象到 Double 对象的无操作转换称为 identity conversion。)

您还可以省略 @specialized 中的类型列表。在这种情况下,该类将专用于所有原始类型:

class Test[@specialized A: ClassTag] {
...

请注意,这会生成更多的类文件。例如,如果所有 Scala 集合类都专门用于所有原始类型,the Scala language library would suddenly become about ten times as large .


根本问题在于:装箱图元的转换规则与未装箱图元的转换规则非常不同。

在这种情况下(使用 Java 语法):

double d = 1.0 / 5.0; // 0.2 as a double primitive value
float f = (float)d; // 0.2f as a float primitive value

按预期工作。从 doublefloat 的转换称为 narrowing primitive conversion .

但这行不通:

java.lang.Double d = 1.0 / 5.0; // 0.2, but in a java.lang.Double object
java.lang.Float f = (java.lang.Float)d; // ClassCastException

java.lang.Doublejava.lang.Float 的缩小或扩大转换是不可能的,因为两者都不是另一个的子类,并且装箱和拆箱转换也不适用。更准确地说,第一行有从doublejava.lang.Double 的隐式装箱转换,但第二行没有应用隐式装箱或拆箱转换。

Scala 使问题更加困惑,因为它试图隐藏区别 - Scala 只有类型 Double,但没有类型 double。根据上下文,Scala 类型 Double 有时(我认为大部分时间)映射到 Java 原始类型 double ,有时映射到 Java 引用类型 java .lang.Double.

关于java - 无法在泛型类中将 Double 转换为 Float,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51537609/

相关文章:

Java,排序分析。堆排序、快速排序 1、快速排序 2、合并排序、给定黑匣子

使用 lambda 函数的 Java 并行化

java - 将两个或多个数据库链接到一个大数据库的术语是什么?

scala - 如何使用现有的 Intellij 项目来推进 SBT?

java - 如何将包注释从 java 转换为 scala

unit-testing - 测试函数是否在 Scala 的给定范围内被调用

scala - 为什么 Scala 无法实例化伴随对象?

java - 加载屏幕 - JFrame 从其他类中设置可见

scala - Scala 符号的目的?

java - 不使用 JFrame 创建屏幕(窗口)