use*_*242 3 java memory literals
System.out.println(5678);
Run Code Online (Sandbox Code Playgroud)
该文字直接在打印语句中使用。但是java是将其直接存储在内存中还是会创建一个自动变量,然后将其存储在内存中?如果第二种情况是正确的,那么如果有人偶然使用相同的变量名偶然访问该变量,将会发生什么?
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方法。
所以通过变量,我们需要istore和iload它的方法。使用文字,我们可以使用将其直接加载到方法中sipush。