Java如何存储文字?

use*_*242 3 java memory literals

System.out.println(5678);
Run Code Online (Sandbox Code Playgroud)

该文字直接在打印语句中使用。但是java是将其直接存储在内存中还是会创建一个自动变量,然后将其存储在内存中?如果第二种情况是正确的,那么如果有人偶然使用相同的变量名偶然访问该变量,将会发生什么?

Zab*_*uza 7

说明

Java在幕后所做的一切对于用户和程序员都是完全隐藏的。

只要您仍在编写Java代码,就不可能将其弄乱。如果您尝试连接JVM进程并注入C代码,或者通过其本机接口与其交互,那么当然可能会有所不同。

JVM如何实际在内存中处理它也完全取决于JVM。内存管理对于Java程序员是完全隐藏的。


字节码

内联变量

话虽如此,让我们看一下此代码段的结果字节代码(请参阅javabytes.io或use javap -c Test.class):

// Source code
public class Test {
    public static void main(String [] args) {
        int value = 4000;
        System.out.println(value);

        System.out.println(5678);
    }
}

// Byte code
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1    // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: sipush        4000
       3: istore_1
       4: getstatic     #2    // Field java/lang/System.out:Ljava/io/PrintStream;
       7: iload_1
       8: invokevirtual #3    // Method java/io/PrintStream.println:(I)V
      11: getstatic     #2    // Field java/lang/System.out:Ljava/io/PrintStream;
      14: sipush        5678
      17: invokevirtual #3    // Method java/io/PrintStream.println:(I)V
      20: return
}
Run Code Online (Sandbox Code Playgroud)

如您所见,这两个变体实际上是相同的。该sipush命令直接加载值,根本没有任何变量的符号。

sipush将a short直接推入堆栈,然后从那里将其拾取invokevirtual并调用print方法(有关详细信息,请参见Java字节码指令列表)。

为什么会这样?好吧,编译器很聪明。它认为变量value没有任何作用,实际上已经完全摆脱了它。它将代码更改为System.out.println(4000)value完全删除。

存在变量

但是我们希望看到一些变量,因此让我们使其更加复杂,以使Java不再通过引入只能在运行时计算的依赖项来内联该变量:

// Source code
public class Test {
    public static void main(String [] args) {
        int value = (int) System.currentTimeMillis();
        System.out.println(value);

        System.out.println(5678);
    }
}

// Byte code
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1    // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2    // Method java/lang/System.currentTimeMillis:()J
       3: l2i
       4: istore_1
       5: getstatic     #3    // Field java/lang/System.out:Ljava/io/PrintStream;
       8: iload_1
       9: invokevirtual #4    // Method java/io/PrintStream.println:(I)V
      12: getstatic     #3    // Field java/lang/System.out:Ljava/io/PrintStream;
      15: sipush        5678
      18: invokevirtual #4    // Method java/io/PrintStream.println:(I)V
      21: return
}   
Run Code Online (Sandbox Code Playgroud)

最后,我们看到了一些可变的动作!变量由方法计算,转换为int,然后通过进行存储istore_1。然后,将它动态地加载到堆栈上iload_1并传递给print方法。

所以通过变量,我们需要istoreiload它的方法。使用文字,我们可以使用将其直接加载到方法中sipush