对 Java 中基元的隐式缩小的想法感到困惑

Confused about the idea of implicit narrowing on primitives in Java

以下看似微不足道的问题动摇了我对原语如何在 Java 中工作的理解的核心。

我遇到了术语 "implicit narrowing" 允许较小范围类型的变量保存较大范围类型的字面值,如果该值落在较小的范围内。
据我所知,Java 只允许在 byte、char、short 和 int 之间。

例如,如果值足够小以适合字节类型的范围,则字节变量可以采用 int。

byte b1 = 3; // allowed even though 3 is an int literal
byte b2 = 350; // compilation error because a byte cannot go beyond positive 127

所以,这很好用:

byte k = 3;

但我不知道为什么下面的行不起作用!!

Byte k = new Byte(3);

除非我把后者改成Byte k = new Byte((byte)3),否则我得到这个编译error:

error: no suitable constructor found for Byte(int)
        Byte k = new Byte(3);                                        
                 ^             
constructor Byte.Byte(byte) is not applicable                    
(actual argument int cannot be converted to byte by method invocation conversion)

error message的最后一段好像有点线索,里面说:

"... actual argument int cannot be converted to 
 byte by method invocation conversion"

那么我的线索问题就变成了:
为什么?! 我的意思是,将一个小的 int 文字分配给一个字节和将一个小的 int 文字传递给一个方法以被 byte 类型的方法参数捕获有什么区别?

我知道如果我传递一个 int 变量就必须使用转换。但是,我没有传递变量。相反,我传递的是一个小文字,编译器应该意识到它对于一个字节来说足够小了!!

我不得不承认它看起来确实很相似,但对于编译器来说,这是两件截然不同的事情。正如您所说,第一个是使用隐式缩小来转换值。然而,在第二个中,您使用的是具有特定签名的构造函数。该签名要求您提供一个字节。这样想:如果他们添加一个构造函数 public Byte(int i) 会发生什么?现在突然间,如果他们允许的话,你正在改变旧代码的含义。我认为这个特定实例是不允许这样做的原因,尽管可能还有其他额外的编译。

文字的赋值和方法调用(包括构造函数)的规则不同。

根据 Java Language Specification (JLS) 8 §3.10,Java 只有 6 种文字类型:IntegerLiteral、FloatingPointLiteral、BooleanLiteral、CharacterLiteral、StringLiteral 和 NullLiteral。

3.10.1进一步说明:

An integer literal is of type long if it is suffixed with an ASCII letter L or l (ell); otherwise it is of type int (§4.2.1).

(§4.2.1 只是类型范围的规范)

关于 IntegerLiteral 的内容有将近 7 页,所以我不打算完整介绍。只要说 int 字面值在赋值期间被向下转换为字节并适当缩短就够了。

但是,它在构造函数中的用法完全不同。由于构造函数是一种方法,因此适用其参数的正常规则。

我尝试快速整理 JLS 中的匹配规则,但这是一个非常长且复杂的部分。不用说,只有在选择运行的方法时,只有扩大转换会自动发生。也就是说,您可以将 int 传递给期望 long 的方法而无需显式强制转换,但您不能将 int 传递给期望 byte 的方法,除非您明确地施放它。

字节 k=新字节 (3);

1) 上面的语句会创建一个类型为"Byte"的对象,记住implicit narrowing只能发生在原始人的.

2) 在创建 Byte 类型的对象时,构造函数会将参数视为 Integer,因此我们必须 显式转换字节的参数为:

字节 k=新字节((字节)3);

在 ASSIGNMENTS 期间,整数文字被隐式向下转换为 byte、char、short 和 int。

因此 byte b1 = 3; 可以正常编译。

请注意,整数文字默认为 int 类型,因此除非您将整数文字分配给 byte 类型的变量或将其显式转换为字节,否则编译器会将文字本身视为 int。

这就是为什么您在 Byte k = new Byte(3); 上出现编译错误的原因在这里,您在构造函数中使用了一个需要字节的 int。