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 <: long
即 int
是 long
的子类型这一事实。
因此,如果 int
是 long
的子类型,那么为 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 <: long
(int
是 long
的子类型)意味着 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
实际上是一个(双精度)浮点文字。 (所有使用 e
或 E
符号的文字都是浮点数,无论文字中是否有明确的小数点。没有 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?
基本上是的。海事组织。
我不认为 int
是 long
或 double
的真正子类型。它们只是相同的整数数据类型,但每个都有不同的关键字和不同的长度。声明 int <: long
和 long <: double
是必需的,因此已知这些数据类型可以无损转换 到一个方向 .
Java byte-code 展示了这些原始数据类型是如何在幕后处理的。通常 long
和 double
只不过是语言结构,因为 int
是正在使用的数据类型:
Note that any referenced "value" refers to a 32-bit int
as per the Java instruction set.
例如:从int
转换为long
完全没有问题,但是当从long
转换为int
时,二进制表示可能会超出位数可用于正确表示值;如果给定的值太大,则需要两个 int
来表示一个 long
变量(通过二进制补码将它们加在一起不会产生相同的值,因为它必须是分成两组位)。查看他们的二进制表示...这些应该使主题显而易见。
我在大学里有这样的说法类'关于子类型关系的注释:
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 <: long
即 int
是 long
的子类型这一事实。
因此,如果 int
是 long
的子类型,那么为 long
类型的变量编写的代码也可以安全地用于 int
类型的变量。
如果我有一段代码,这对我来说没有意义
long x = 2e63 - 1
那么通过上面的语句,我可以使用
int x = 2e63 - 1
这显然会导致溢出。
在我看来,语句的第二部分应该颠倒过来,即“如果为类型 T 的变量编写的代码可以安全地用于类型 S 的变量,则 T 是 S 的子类型”。但是,在我寻找答案的过程中,似乎在其他 类' 其他注释中重复了此声明。我只是误会了吗?也许我给出的例子不是声明的有效案例?
So if
int
is a subtype oflong
, then code written for variables of typelong
can also be safely used on variables of typeint
.
好的...我明白了这是对子类型的有效描述。
然而,这并不是 JLS 实际指定和使用 子类型关系 <:
的方式。在 JLS 中,子类型化主要是关于 values 的使用方式。
因此,例如,int <: long
(int
是 long
的子类型)意味着 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
实际上是一个(双精度)浮点文字。 (所有使用 e
或 E
符号的文字都是浮点数,无论文字中是否有明确的小数点。没有 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?
基本上是的。海事组织。
我不认为 int
是 long
或 double
的真正子类型。它们只是相同的整数数据类型,但每个都有不同的关键字和不同的长度。声明 int <: long
和 long <: double
是必需的,因此已知这些数据类型可以无损转换 到一个方向 .
Java byte-code 展示了这些原始数据类型是如何在幕后处理的。通常 long
和 double
只不过是语言结构,因为 int
是正在使用的数据类型:
Note that any referenced "value" refers to a 32-bit
int
as per the Java instruction set.
例如:从int
转换为long
完全没有问题,但是当从long
转换为int
时,二进制表示可能会超出位数可用于正确表示值;如果给定的值太大,则需要两个 int
来表示一个 long
变量(通过二进制补码将它们加在一起不会产生相同的值,因为它必须是分成两组位)。查看他们的二进制表示...这些应该使主题显而易见。