对 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。
以下看似微不足道的问题动摇了我对原语如何在 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。