JVM指令-sload

JVM instructions - sload

估计是一道基础题,但是为什么没有sload指令呢? 为什么可以加载除 short 之外的所有图元? (有saload,但还是...)

对于:

public class ShortTest {
    public void test() {
        short i = 1;
        System.out.print(i);
    }
}

编译器仍然使用iload_1。是否因为 short 是 16 位类型而处理器处理更好的 32 位(因为所有现代处理器都是 32/64 位)?

因为所有局部变量都至少占用一个32位槽。字节也是如此。

参考JVM规范,§2.11.1. Types and the Java Virtual Machine:

Note that most instructions in Table 2.11.1-A do not have forms for the integral types byte, char, and short. None have forms for the boolean type. A compiler encodes loads of literal values of types byte and short using Java Virtual Machine instructions that sign-extend those values to values of type int at compile-time or run-time. Loads of literal values of types boolean and char are encoded using instructions that zero-extend the literal to a value of type int at compile-time or run-time. Likewise, loads from arrays of values of type boolean, byte, short, and char are encoded using Java Virtual Machine instructions that sign-extend or zero-extend the values to values of type int. Thus, most operations on values of actual types boolean, byte, char, and short are correctly performed by instructions operating on values of computational type int.

值得一提的是,在Java中,任何不涉及long的整数运算都会得到int的结果,无论输入是否为bytecharshortint

所以一行像

short i = 1, j = 2, k = i + j;

不会编译,但需要类型转换,例如

short i = 1, j = 2, k = (short)(i + j);

并且此类型转换将是涉及 short 的唯一指标。撇开调试提示不谈,字节码中没有局部变量的正式声明,只有确定其类型的值赋值。所以 short 类型的局部变量根本不存在。上面的代码编译为

     0: iconst_1
     1: istore_1
     2: iconst_2
     3: istore_2
     4: iload_1
     5: iload_2
     6: iadd
     7: i2s
     8: istore_3

的编译形式相同
int i = 1, j = 2, k = (short)(i + j);

但请注意,变量的编译时类型可以更改编译器在重载情况下为调用选择的方法。如果类型带有不同的语义,这一点尤其重要,例如 print(boolean)print(char)。虽然传递给方法的值在任何一种情况下都具有 int 类型,但结果完全不同。

编译器强制实施的另一个差异示例是

{
    int i = 1;
    i++;
}
{
    short s = 1;
    s++;
}

编译为

     0: iconst_1
     1: istore_1
     2: iinc          1, 1
     5: iconst_1
     6: istore_1
     7: iload_1
     8: iconst_1
     9: iadd
    10: i2s
    11: istore_1

因此,由于计算始终以 32 位执行,因此编译器插入必要的代码以将结果截断为 short 以进行第二次增量。再次注意没有变量声明,因此代码与

的编译形式相同
int i = 1;
i++;
i = 1;
i = (short)(i+1);

也值得一看 the Verification Type System,因为验证者将检查所有从局部变量到局部变量的传输的有效性:

The type checker enforces a type system based upon a hierarchy of verification types, illustrated below.

Verification type hierarchy:

                             top
                 ____________/\____________
                /                          \
               /                            \
            oneWord                       twoWord
           /   |   \                     /       \
          /    |    \                   /         \
        int  float  reference        long        double
                     /     \
                    /       \_____________
                   /                      \
                  /                        \
           uninitialized                    +------------------+
            /         \                     |  Java reference  |
           /           \                    |  type hierarchy  |
uninitializedThis  uninitialized(Offset)    +------------------+  
                                                     |
                                                     |
                                                    null

因此,与 Java 语言类型相比,类型系统得到了简化,并且验证者不介意,例如如果您将 boolean 值传递给需要 char 的方法,因为两者都是 int 类型。