System.out.println(5678);
这个字面值直接被用于打印语句中。但是Java是直接将其存储在内存中还是创建一个自动变量然后将其存储在那里?如果第二种情况是真的,那么如果有人意外地使用相同的变量名访问该变量会发生什么?
Java在幕后所做的一切都完全对用户和程序员隐藏。
只要你仍然写Java代码,就不可能搞乱它。当然,如果你尝试连接JVM进程并注入C代码或通过其本地接口与其交互,情况可能会有所不同。
在Java中,内存管理也完全由JVM处理。程序员无法直接管理内存。
话虽如此,让我们来看一下这个片段的结果字节码(请参见javabytes.io或使用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
}
// 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
}
最后我们看到了一些变量操作!该变量由方法计算,转换为int
,然后通过istore_1
进行存储。然后,通过iload_1
将其动态加载到堆栈上,并传递给打印方法。
因此,对于变量,我们需要使用istore
和iload
将其传递给方法。对于文字,我们可以直接使用sipush
将其加载到方法中。
class test {
public static void main(String[] args) {
System.out.println(5678);
System.out.println("test string");
}
}
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: sipush 5678
6: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
9: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
12: ldc #19 // String test string
14: invokevirtual #21 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
17: return
-verbose
标志,它也会打印常量池,你可以查找 #19
并看到它是字符串 test string
。简短回答:不行!你不能在编译时访问它们。
Java将字面量存储在permgen space
内存中,无法通过变量名称在编译时访问。这也取决于JVM如何实现它。
例如,在下面的代码中,如果我们谈论String
字面量,Java可能会将"sameSame"
存储在某个内存位置(String Pool)中,然后对两个方法都使用它,而不是创建相同的字符串两次。
private static String test1(){
return "sameSame";
}
private static String test2(){
return "sameSame";
}
System.out.println(2 + 3)
,那么值2和3在编译后的代码中甚至不存在(因为它们自动变成了5)。 - MC Emperor