为什么在Java中无法将float[]转换为double[]?

5
我正在使用一个返回二维 float 数组作为结果的 API。我想使用流 API 中的 flatMap 方法来处理这些数据,但是我需要将 double 数组的数组传递给它的方法。我尝试通过将 float[][] 强制转换为 double[][] 来解决这个问题,但是即使使用 float[] 也不能成功。以下是 JShell 会话转储:
-> new float[] {1.02f, 4.32f, 65.4f}
  Expression value is: [F@2b98378d
    assigned to temporary variable $1 of type float[]

-> double[] arrayOfDoubles = (double[]) $1
  Error:
  incompatible types: float[] cannot be converted to double[]
  double[] arrayOfDoubles = (double[]) $1;

所以,我的问题是:为什么我们不能将`float[]`转换为`double[]`,而从`float`转换为`double`却是合法的呢?

6
思考在进行数据类型转换时需要发生什么,并了解每种数据类型在内存中的存储方式。 - Mysticial
你为什么一开始就要使用浮点数? - RealSkeptic
2个回答

6
如果你把一个 float[] 数组的内存空间当作 double[] 数组来看待,那么数组中的偏移量就会全部错误。因此,当你查看 double #1 时,你将会看到 float #1 和 float #2 的一部分。这就是为什么你需要转换而不仅仅是强制类型转换。

换句话说,Java 语言规范没有提供这样的转换形式的强制类型转换语法。

回到你最初的问题,以下是来自 Brian Goetz 的绝佳技巧:

DoubleStream ds = IntStream.range(0, floatArray.length)
                       .mapToDouble(i -> floatArray[i]);

最后,通过上述技巧,这是您的flatMap DoubleStream:

DoubleStream ds = Arrays.stream(float2dArray)
        .flatMapToDouble(floatArray -> IntStream.range(0, floatArray.length)
                .mapToDouble(i -> floatArray[i]));

有没有特定的原因要使用带有数组访问器的IntStream.range而不是Arrays.stream?如果我没记错,它还为原始流提供了重载。 - Wietlol
@Wietlol 你可以流式传输 float[][],因为每个 float[] 都是一个对象,所以它可以使用 Object[] 的重载方法。然而,你不能流传输 float[],因为该签名没有重载方法!有关该部分的详细信息,请查看 Brian 的链接回答(点击他的上面的名称)。 - Patrick Parker
啊,他们只为float[]添加了Arrays.stream,而没有为int、long和double添加。有道理...我的意思是要做范围。 - Wietlol

6

数组是引用类型,即使是具有原始元素的数组也是如此。

将引用类型强制转换实际上并不会对基础对象做任何事情:它只是告诉编译器“相信我,我知道比你更多的类型信息:这个指向 Foo 的引用可以安全地视为指向 Bar 的引用”。

除非编译器可以证明强制转换是不安全的,否则它会信任你并允许你这样做;程序员需要检查它是否安全,否则就会在运行时面临 ClassCastException。

因此,将 float[] 强制转换为 double[] 不会改变基础对象,它只是改变了编译器允许您对其进行的操作。

但是,一旦您可以将其视为 double[],您就可以要求 JVM 将 double 分配给该数组的元素。 double 无法适应 float,因此有两种选择:

  • 检查值是否在范围内,并进行强制转换。但是,这样会损失精度,并且可能很难调试;
  • 或者,通过防止您将 float[] 分配给 double[] 来防止您首先陷入这种情况。

第二个选择更简单,这就是他们的选择。


请注意,您可以通过通过 Object 进行强制转换来将 float[] 强制转换为 double[]

float[] f = ...
double[] d = (double[]) (Object) f;

但是,如果f为空,这将在运行时失败。


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