什么是“可能的有损转换"?意思是我该如何解决? [英] What does "possible lossy conversion" mean and how do I fix it?

查看:66
本文介绍了什么是“可能的有损转换"?意思是我该如何解决?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java 新手经常被编译错误消息搞糊涂,例如:

New Java programmers are often confused by compilation error messages like:

不兼容的类型:从 double 到 int 的可能有损转换"

"incompatible types: possible lossy conversion from double to int"

对于这行代码:

int squareRoot = Math.sqrt(i);

一般来说,可能的有损转换"错误消息是什么意思,您如何解决?

In general, what does the "possible lossy conversion" error message mean, and how do you fix it?

推荐答案

首先,这是一个编译错误.如果您在运行时在异常消息中看到它,那是因为您运行的程序有编译错误1.

First of all, this is a compilation error. If you ever see it in an exception message at runtime, it is because you have have run a program with compilation errors1.

消息的一般形式是这样的:

The general form of the message is this:

不兼容的类型:从 的可能有损转换";

"incompatible types: possible lossy conversion from <type1> to <type2>"

其中 都是原始数字类型;即 bytecharshortintlongfloatdouble.

where <type1> and <type2> are both primitive numeric types; i.e. one of byte, char, short, int, long, float or double.

当您的代码尝试从 进行隐式转换时,会发生此错误.type2> 但转换可能会有损.

This error happens when your code attempts to do an implicit conversion from <type1> to <type2> but the conversion could be lossy.

在问题的例子中:

  int squareRoot = Math.sqrt(i);

sqrt 方法产生一个 double,但从 doubleint 的转换可能是有损的.

the sqrt method produces a double, but a conversion from double to int is potentially lossy.

好吧,让我们看几个例子.

Well lets look at a couple of examples.

  1. longint 的转换是一种潜在的有损转换,因为有 long 值没有对应的 int 值.例如,任何大于 2^31 - 1 的 long 值都太大而无法表示为 int.同样,任何小于 -2^31 的数都太小了.

  1. A conversion of a long to an int is a potentially lossy conversion because there are long values that do not have a corresponding int value. For example, any long value that is greater than 2^31 - 1 is too large to be represented as an int. Similarly, any number less than -2^31 is too small.

intlong 的转换不是有损转换,因为每个 int 值都有一个对应的 long 值.

A conversion of an int to a long is NOT lossy conversion because every int value has a corresponding long value.

floatlong 的转换是一种潜在的有损转换,因为 float 值太大或太大小以表示为 long 值.

A conversion of a float to an long is a potentially lossy conversion because there float values that are too large or too small to represent as long values.

longfloat 的转换不是有损转换,因为每个 long 值都有一个对应的 float 值.(转换后的值可能不太精确,但损失"并不意味着……在这种情况下.)

A conversion of an long to a float is NOT lossy conversion because every long value has a corresponding float value. (The converted value may be less precise, but "lossiness" doesn't mean that ... in this context.)

这些是所有可能有损的转换:

These are all the conversions that are potentially lossy:

  • shortbytechar
  • charbyteshort
  • intbyteshortchar
  • longbyteshortcharint
  • floatbyteshortcharint>长
  • doublebyteshortcharintlongfloat.
  • short to byte or char
  • char to byte or short
  • int to byte, short or char
  • long to byte, short, char or int
  • float to byte, short, char, int or long
  • double to byte, short, char, int, long or float.

消除编译错误的方法是添加类型转换.例如;

The way to make the compilation error go away is to add a typecast. For example;

  int i = 47;
  int squareRoot = Math.sqrt(i);         // compilation error!

变成

  int i = 47;
  int squareRoot = (int) Math.sqrt(i);   // no compilation error

但这真的能解决问题吗?考虑到 47 的平方根是 6.8556546004 ... 但是 squareRoot 将得到值 6.(转换将截断,而不是舍入.)

But is that really a fix? Consider that the square root of 47 is 6.8556546004 ... but squareRoot will get the value 6. (The conversion will truncate, not round.)

这个呢?

  byte b = (int) 512;

这导致 b 获得值 0.将较大的int类型转换为较小的int类型是通过屏蔽掉高位来完成的,512的低8位全为零.

That results in b getting the value 0. Converting from a larger int type to a smaller int type is done by masking out the high order bits, and the low-order 8 bits of 512 are all zero.

简而言之,您不应该简单地添加类型转换,因为它可能不会为您的应用程序做正确的事情.

In short, you should not simply add a typecast, because it might not do the correct thing for your application.

相反,您需要了解为什么您的代码需要进行转换:

Instead, you need to understand why your code needs to do a conversion:

  • 发生这种情况是否是因为您在代码中犯了一些其他错误?
  • 是否应该是不同的类型,以便此处不需要有损转换?
  • 如果需要进行转换,类型转换是否会执行正确的无声有损转换?
  • 或者您的代码是否应该进行一些范围检查并通过抛出异常来处理不正确/意外的值?

第一个例子:

for (double d = 0; d < 10.0; d += 1.0) {
    System.out.println(array[d]);  // <<-- possible lossy conversion
}

这里的问题是数组索引值必须是int.所以d 必须从double 转换成int.通常,使用浮点值作为索引没有意义.要么有人认为 Java 数组的工作方式类似于(比如)Python 字典,要么他们忽略了浮点运算通常不准确的事实.

The problem here is that array index value must be int. So d has to be converted from double to int. In general, using a floating point value as an index doesn't make sense. Either someone is under the impression that Java arrays work like (say) Python dictionaries, or they have overlooked the fact that floating-point arithmetic is often inexact.

解决办法是重写代码,避免使用浮点值作为数组索引.(添加类型转换可能是一个不正确的解决方案.)

The solution is to rewrite the code to avoid using a floating point value as an array index. (Adding a type cast is probably an incorrect solution.)

第二个例子:

for (long l = 0; l < 10; l++) {
    System.out.println(array[l]);  // <<-- possible lossy conversion
}

这是上一个问题的变体,解决方法是一样的.不同之处在于根本原因是 Java 数组仅限于 32 位索引.如果你想要一个类似数组"具有超过 231 - 1 个元素的数据结构,您需要定义或找到一个类来完成.

This is a variation of the previous problem, and the solution is the same. The difference is that the root cause is that Java arrays are limited to 32 bit indexes. If you want an "array like" data structure which has more than 231 - 1 elements, you need to define or find a class to do it.

考虑一下:

public class User {
    String name;
    short age;
    int height;

    public User(String name, short age, int height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public static void main(String[] args) {
        User user1 = new User("Dan", 20, 190);
    }
}

使用 Java 11 编译上述内容会得到以下结果:

Compiling the above with Java 11 gives the following:

$ javac -Xdiags:verbose User.java 
User.java:20: error: constructor User in class User cannot be applied to given types;
    User user1 = new User("Dan", 20, 190);
                 ^
  required: String,short,int
  found: String,int,int
  reason: argument mismatch; possible lossy conversion from int to short
1 error

问题在于字面量20是一个int,而构造函数中对应的参数被声明为一个short.将 int 转换为 short 是有损的.

The problem is that the literal 20 is an int, and the corresponding parameter in the constructor is declared as a short. Converting an int to a short is lossy.

示例:

public int compute() {
    long result = 42L;
    return result;  // <<-- possible lossy conversion
}

return(带有值/表达式)可以被认为是对返回值的赋值".但是不管怎么想,都需要将提供的值转换为方法的实际返回类型.可能的解决方案是添加类型转换(表示我承认有损")或更改方法的返回类型.

A return (with a value / expression) could be thought of an an "assignment to the return value". But no matter how you think about it, it is necessary to convert the value supplied to the actual return type of the method. Possible solutions are adding a typecast (which says "I acknowledge the lossy-ness") or changing the method's return type.

考虑一下:

int a = 21;
byte b1 = a;   // <<-- possible lossy conversion
byte b2 = 21;  // OK

这是怎么回事?为什么允许一个版本而另一个版本不允许?(毕竟他们做"同样的事情!)

What is going on? Why is one version allowed but the other one isn't? (After all they "do" the same thing!)

首先,JLS 声明 21 是一个类型为 int 的数字文字.(没有 byteshort 文字.)所以在这两种情况下,我们都将 int 分配给 byte.

First of all, the JLS states that 21 is an numeric literal whose type is int. (There are no byte or short literals.) So in both cases we are assigning an int to a byte.

在第一种情况下,错误的原因是并非所有 int 值都适合 byte.

In the first case, the reason for the error is that not all int values will fit into a byte.

在第二种情况下,编译器知道 21 是一个总是适合 byte 的值.

In the second case, the compiler knows that 21 is a value that will always fit into a byte.

技术解释是在赋值上下文中,允许将原始收缩转换字节charshort 如果以下都为真:

The technical explanation is that in an assignment context, it is permissible to perform a primitive narrowing conversion to a byte, char or short if the following are all true:

  • 该值是编译时常量表达式(包括文字)的结果.
  • 表达式的类型为byteshortcharint.
  • 被分配的常量值在目标"域中是可表示的(没有损失).类型.
  • The value is the result of a compile time constant expression (which includes literals).
  • The type of the expression is byte, short, char or int.
  • The constant value being assigned is representable (without loss) in the domain of the "target" type.

请注意,这仅适用于赋值语句,或者更专业地用于赋值上下文.因此:

Note that this only applies with assignment statements, or more technically in assignment contexts. Thus:

Byte b4 = new Byte(21);  // incorrect

给出编译错误.

1 - 例如,Eclipse IDE 有一个选项,它允许您忽略编译错误并仍然运行代码.如果选择此选项,IDE 的编译器将创建一个 .class 文件,其中包含错误的方法在被调用时将引发未经检查的异常.异常信息会提到编译错误信息.

1 - For instance, the Eclipse IDE has an option which allows you to ignore compilation errors and run the code anyway. If you select this, the IDE's compiler will create a .class file where the method with the error will throw an unchecked exception if it is called. The exception message will mention the compilation error message.

这篇关于什么是“可能的有损转换"?意思是我该如何解决?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆