class常量池
java文件在编译成class文件后,在class文件中会生成一个常量池,用于存放代码的字面量、符号引用,如static、void、public等等。这个常量池称为class常量池。用javap命令可生成一个可阅读的JVM字节码指令文件:
javap -v ScheduledBlockChainTask.class
红框标出的就是class常量池信息,常量池中主要存放两大类常量:字面量和符号引用。
- int a = 1;
- int b = 2;
- int c = "abcdefg";
- int d = "abcdefg
三种字符串操作
String s = "lamu"; // s指向常量池中的引用
String s1 = new String("zhuge"); // s1指向内存中的对象引用
- String s1 = new String("zhuge");
- String s2 = s1.intern();
- System.out.println(s1 == s2); //false
intern方法返回的是对象在字符串常量池中的引用。在jdk6及以下的版本中,如果字符串常量池中存在该对象,则返回字符串常量池中对象的引用。如果没有,则将该对象添加到字符串常量池中,返回字符串常量池中该对象的引用。在jdk6以上的版本中,如果字符串常量池中存在该对象,则返回字符串常量池中对象的引用。如果没有,则在堆中查看是否存在该对象,如果有,将堆中该对象的引用放入字符串常量池中并返回。
String拼接符“+”底层会做什么
如果在编译阶段,能确定拼接前后对象的值,那么会在编译阶段直接拼接,将最终的值放入字符串常量池。如果在编译阶段不能知道拼接前后对象的值,那么会在运行阶段创建一个拼接了前后字段值的对象在堆和字符串常量池中。
- String s1 = new String("he") + new String("llo");
- String s2 = s1.intern();
- System.out.println(s1 == s2);
- // 在 JDK 1.6 下输出是 false,创建了 6 个对象
- // 在 JDK 1.7 及以上的版本输出是 true,创建了 5 个对象
- // 当然我们这里没有考虑GC,但这些对象确实存在或存在
-
-
- String s0="hello";
- String s1="hello";
- String s2="he" + "llo";
- System.out.println( s0==s1 ); //true
- System.out.println( s0==s2 ); //true s2会在编译期被优化成"hello"。
-
-
- String s0="hello";
- String s1=new String("hello");
- String s2="he" + new String("llo");
- System.out.println( s0==s1 ); // false s0在常量池,s1在堆中
- System.out.println( s0==s2 ); // false new String("llo")没法在编译期优化,所以s2最终在堆中生成
- System.out.println( s1==s2 ); // false s1和s2都在堆中,但它们是new出来的两个不同对象
-
-
- String a = "ab";
- String bb = "b";
- String b = "a" + bb;
- System.out.println(a == b); // false 变量bb在编译期不可知,无法优化
-
-
- String a = "ab";
- final String bb = "b";
- String b = "a" + bb;
- System.out.println(a == b); // true bb用final修饰,编译期可知,b在编译期可被优化成"ab"
-
-
- String a = "ab";
- final String bb = getBB();
- String b = "a" + bb;
- System.out.println(a == b); // false 方法即使用final修饰,它也要到运行期来生成动态链接执行代码,因此编译期不可知,无法优化
- private static String getBB() {
- return "b";
- }
-