Java 中原始类型的子类型化

Sub-typing on Primitive types in Java

我在大学里有这样的说法类'关于子类型关系的注释:

T is a subtype of S if code written for variables of type S can also be safely used on variables of type T

Java Language Spec 的第 4.10.1 节描述了 Java 中原始类型之间的子类型化关系。特别是,根据 JLS,我使用 int <: longintlong 的子类型这一事实。

因此,如果 intlong 的子类型,那么为 long 类型的变量编写的代码也可以安全地用于 int 类型的变量。

如果我有一段代码,这对我来说没有意义

long x = 2e63 - 1

那么通过上面的语句,我可以使用

int x = 2e63 - 1

这显然会导致溢出。

在我看来,语句的第二部分应该颠倒过来,即“如果为类型 T 的变量编写的代码可以安全地用于类型 S 的变量,则 T 是 S 的子类型”。但是,在我寻找答案的过程中,似乎在其他 类' 其他注释中重复了此声明。我只是误会了吗?也许我给出的例子不是声明的有效案例?

So if int is a subtype of long, then code written for variables of type long can also be safely used on variables of type int.

好的...我明白了这是对子类型的有效描述。

然而,这并不是 JLS 实际指定和使用 子类型关系 <: 的方式。在 JLS 中,子类型化主要是关于 values 的使用方式。

因此,例如,int <: longintlong 的子类型)意味着 int 值可用于需要 long值。

这里有一些例子:

 int i = 1;
 long l = i;            // OK - int used where a long is needed
 long ll = i + 1L;      // OK - int used where a long is needed

 public void methodWithLongArg(long arg) { ... }

 methodWithLongArg(i);  // OK - int used where a long is needed

请注意,在上面的每一个中,JLS 都表示 原始扩展转换 用于将 int 值转换为 long值。

那么你的例子呢:

long x = 2e63 - 1;   // NOT OK
int i = 2e63 - 1;    // NOT OK

事实上, 都不合法 Java。文字 2e63 实际上是一个(双精度)浮点文字。 (所有使用 eE 符号的文字都是浮点数,无论文字中是否有明确的小数点。没有 f 或 [=28= 的浮点文字] 后缀表示 double 值。)因此 2e63 - 1 的计算结果为 double,而 double 不能分配给 long(或 int)除非你明确地投射它。

这与子类型一致。 JLS 规则意味着 long <: double。所以这意味着 long 可以在需要 double 的上下文中使用。但在上面,我们需要在需要 long(或 int)的上下文中使用 double。这就是子类型关系所允许的相反

其实你的例子还有一个问题。 263写成(十进制)9223372036854775808L。并且只有在它前面有一个一元减号运算符时才能使用它。同样,它不能用 Java 二进制、八进制或十六进制文字语法表示为 long 文字。


我认为真正的问题是你误解了你的讲师所说的话。

实际上说的是为超类型编写的代码可以应用于子类型的值。

因此,在我的示例中,methodWithLongArg(long arg) 方法是为超类型编写的代码;即 long。它可以在子类型的值上使用(调用);即 int 变量的值。

Am I simply misunderstanding it? Maybe the example I gave is not a valid case of the statement?

基本上是的。海事组织。

我不认为 intlongdouble 的真正子类型。它们只是相同的整数数据类型,但每个都有不同的关键字和不同的长度。声明 int <: longlong <: double 是必需的,因此已知这些数据类型可以无损转换 到一个方向 .

Java byte-code 展示了这些原始数据类型是如何在幕后处理的。通常 longdouble 只不过是语言结构,因为 int 是正在使用的数据类型:

Note that any referenced "value" refers to a 32-bit int as per the Java instruction set.

例如:从int转换为long完全没有问题,但是当从long转换为int时,二进制表示可能会超出位数可用于正确表示值;如果给定的值太大,则需要两个 int 来表示一个 long 变量(通过二进制补码将它们加在一起不会产生相同的值,因为它必须是分成两组位)。查看他们的二进制表示...这些应该使主题显而易见。