java - JVM指令-sload

标签 java jvm bytecode

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

对于:

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

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

最佳答案

引用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 类型。

关于java - JVM指令-sload,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57673666/

相关文章:

java - Selenium 使用当前 session 重新打开浏览器

java - java字节码中方法表和方法体之间包含哪些信息

java - 什么决定了 java 字节码 try catch 处理程序的堆栈图帧的局部变量?

python - Python中的`goto`

java - 如何在 eclipse 中将 .war 文件作为 java web 项目依赖项包含在内?

java - 通用工厂类实例化

java - 了解 Swing 计时器

java - 逃逸分析是否有助于 JVM 在堆栈上分配数组?

Java NIO 与非 NIO 性能对比

java - 无法加载 JVM