为啥允许从 int 到 byte 但不允许从 long 到 int 的隐式缩小转换?

Posted

技术标签:

【中文标题】为啥允许从 int 到 byte 但不允许从 long 到 int 的隐式缩小转换?【英文标题】:Why is an implicit narrowing conversion allowed from int to byte but not from long to int?为什么允许从 int 到 byte 但不允许从 long 到 int 的隐式缩小转换? 【发布时间】:2018-06-10 01:05:44 【问题描述】:

考虑下面的代码sn-p:

// automatic casting works for int to byte conversion as integer literal 127
// is in the range for byte
byte b1 = 127; //OK

// automatic casting doesn't work for long to int conversion 
// even if long literal is in the range of int.
int i5 = 100L; // NOT OK - compilation error

对这种行为有什么解释吗?

为什么int转byte不需要显式转换,long转int需要显式转换?

How does Java convert int into byte? 的问题不同。这是关于int值超出范围时将int隐式转换为byte的问题。

【问题讨论】:

Java 不喜欢转换的丢失;它不知道没有真正的损失。 但是为什么在int到字节转换的情况下会这样呢? @AniketSahrawat 同样是 int 和 byte.. 更新问题更清晰:为什么在 int 到 byte 的情况下不需要显式转换,但 long 到 int 需要显式转换? 因为127 没有文字后缀,Java 能够将其转换为适当的类型。 【参考方案1】:

Java 编译器通常隐式接受扩展转换(例如,byteint),因为不会丢失信息(int 的范围大于 byte 的范围)。

缩小转换范围(例如,longint,如您的情况)可能会导致信息丢失,因此通常需要显式转换。

请参阅this 类似问题和this。 Java Language Specification的相关部分:

将表达式的值(第 15.26 节)分配给变量时发生赋值转换:必须将表达式的类型转换为变量的类型。

...

此外,如果表达式是 byte、short、char 或 int 类型的常量表达式(第 15.28 节):

如果变量的类型是 byte、short 或 char,并且常量表达式的值可以在变量的类型中表示,则可以使用缩小原语转换。

如果变量的类型为:

字节和常量表达式的值可以用字节类型表示

Short 并且常量表达式的值可以用 short 类型表示。

字符和常量表达式的值可以用char类型表示。

(强调我的)


由于我们使用的是数字字面量,所以我们特别在处理常量表达式这一事实引起了一些混淆。上面的规范也需要仔细阅读。

澄清一些事情并直接回答一些OP的查询:

    为什么一种类型的窄化支持隐式窄化而不支持另一种类型的窄化?

    即。为什么byte b1 = 127 隐式工作,而int i5 = 100L 不工作?

    byte b1 = 127 执行隐式转换(参见上面引用中的粗体文本),“常量表达式的值可以在类型字节中表示”。也就是说,127 可以用byte 表示,因此转换是隐式的。如果您尝试byte b1 = 128,您将收到关于不兼容类型的错误,因为128 不能由byte 表示。 完全允许我们在这里进行隐式转换的唯一原因是因为我们使用了常量表达式

    我们没有在int i5 = 100L 中获得隐式转换(即使 100 在int 的范围内),因为它根本没有在允许的隐式转换中列出(变量的类型int 不是一个byteshortchar)。

    我们也没有在byte a = 0L 中获得隐式转换,这一次是因为常量表达式是long 类型,而不是byteshortcharint 类型。

    普通程序员如何知道隐式允许哪种窄化转换?

    仅当您将 常量表达式 分配给变量时,才会发生隐式缩小转换。在这些情况下,隐式转换很好,因为我们不想一直编写像byte b = (byte)0 这样的代码。同时,我们确实希望在我们写像byte b = 128 这样的东西时收到警告,因为它没有直观的行为。

    当我们不分配常量表达式时(例如int x = 0; byte b = x;),我们总是希望在进行潜在的有损转换时得到警告,因为它们很危险 - 所以在这种情况下显式转换也会使感觉。

【讨论】:

我不会在这里添加任何内容,只是说这只是官方文档的复制/粘贴。 谢谢 hnefatl。我仍然无法理解-:1.为什么一种类型的缩小而不支持其他类型的隐式转换。 2. 普通程序员如何知道哪些窄化转换是隐式允许的,哪些需要显式努力。 - 或者程序员应该等到编译错误发生?如果是这样,那就太奇怪了! @simpleDev 我试图在我的编辑中回答这些问题,如果还有什么不清楚的地方请告诉我。 @RomanC 我已经编辑了我的帖子,包括对语言规范相关部分的解释,以及对这种特定情况的分析。 您不了解规范。这被你错误地解释了。我不是说错了,而是意思不一样。

以上是关于为啥允许从 int 到 byte 但不允许从 long 到 int 的隐式缩小转换?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 &mut self 允许借用 struct 成员,但不允许将 self 借用到不可变方法?

为啥 curl 允许使用文件 URL 方案,但不允许使用 wget

为啥首先允许指针从非常量到常量的隐式转换?

为啥浏览器允许设置一些没有 CORS 的标头,但不允许设置其他标头?试图避免预检

为啥将“0”添加到 int 数字允许转换为 char?

为啥我收到错误,因为不允许使用 nodejs 将文件从一个文件夹复制到另一个文件夹?