Java 常量池
Java 常量池
常量池入口放置 u2类型的数据,代表常量池容量计数值 constant_pool_count 。 u2类型是 什么
基本类型包装类和常量池
- Byte Short Integer, Long Character, Boolean:
Integer如果超过范围 就会去创建新的对象
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 400;
Integer i4 = 400;
System.out.println(i1 == i2); //true
System.out.println(i3 == i4); //false
double d1 = 1.1;
double d2 = 1.1;
Double d3 = 1.1;
Double d4 = 1.1;
System.out.println(d1 == d2); // true
System.out.println(d3 == d4); // false
两种浮点数类型的包装类Float,Double并没有实现常量池技术。
Double i1=1.2;
Double i2=1.2;
System.out.println(i1==i2);//输出false
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
System.out.println("i1 = i2\t"+ (i1==i2)); //true
System.out.println("i1 = i2 + i3\t"+ (i1 == (i2 + i3))); //true
System.out.println("i4 = i5\t"+ (i4==i5)); //false
System.out.println("i4 = i5 + i6\t"+ (i4 ==i5 + i6)); //true
System.out.println("40 = i5 + i6 "+ (40 == i5+i6)); // true
首先i5和i6进行自动拆箱操作,进行数值相加,即i4 == 40。
然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。
String类和对象池
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2); //false
s1 常量池 中对象; s2 在堆上创建 新对象。
String s3 = "hello";
String s4 = "world";
String s5 = "helloworld";
String s6 = s3+s4;
System.out.println(s5 == s6); //false
String 重载了 + 操作符 字符串拼接相当于 重新创建新的字符串。 因此, "hello" + "world" 相当于创建 新的 "helloworld"
java基础:字符串的拼接 http://www.jianshu.com/p/88aa19fc21c6
public static final String S7 = "ab";
public static final String S8 = "cd";
public static void main(String[] args){
String s9 = "abcd";
System.out.println(s9 == (S7+S8)); //true
}
S7 S8为常量。 编译时确定。
public static final String S7;
public static final String S8;
static {
S7 = "ab";
S8 = "cd";
}
public static void main(String[] args){
String s9 = "abcd";
System.out.println(s9 == (S7+S8));// false
}
// 此时,由于 S7 S8没有 定义时赋值, 相当于 变量,值在运行时确定。而不是编译时。
String s1 = new String("xyz");
1.类加载,一个类只进行一次。 "xyz"在类加载时就已经创建并驻留了(如果该类被加载之前已经有"xyz"字符串被驻留过则不需要重复创建用于驻留的"xyz"实例)。
驻留的字符串是放在全局共享的字符串常量池中的。
2.在这段代码后续被运行的时候,"xyz"字面量对应的String实例已经固定了,不会再被重复创建。
所以这段代码将常量池中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s1 持有。
这条语句创建了2个对象。 一个堆上的对象,一个引用对象 ?
String 常量池 String.intern()用法
- 直接使用双引号声明出来的String对象会直接存储在常量池中。
- 如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中
//Other.java
package basics.other;
public class Other {
public static String hello = "hello";
}
//StringTest.java
package basics;
public class StringTest {
public static void main(String[] args){
String hello = "hello";
String lo = "lo";
System.out.println(hello == "hello"); //true
System.out.println(basics.other.Other.hello == hello); //true
System.out.println(Other.hello == hello); //ture
System.out.println(hello == "hel"+"lo"); //true
System.out.println(hello == "hel"+lo); //false
System.out.println(hello == ("hel"+lo).intern()); //true
}
}
class Other{
static String hello = "hello";
}
在同包同类下,引用自同一String对象.
在同包不同类下,引用自同一String对象.
在不同包不同类下,依然引用自同一String对象.
在编译成.class时能够识别为同一字符串的,自动优化成常量,引用自同一String对象.
在运行时创建的字符串具有独立的内存地址,所以不引用自同一String对象. “+” 操作符 创建新对象。
《深入Java虚拟机 》 第6章 Java class文件
《深入理解Java7》 第8章 Java源代码和字节代码操作
《深入理解Java虚拟机 JVM高级特性与最佳实践》6.3
参考资料
http://www.jianshu.com/p/c7f47de2ee80
Java中的自动装箱与拆箱
http://droidyue.com/blog/2015/04/07/autoboxing-and-autounboxing-in-java/
Java堆、栈和常量池以及相关String的详细讲解(经典中的经典) (未看)
http://www.cnblogs.com/xiohao/p/4296088.html
深入解析String#intern
http://tech.meituan.com/in_depth_understanding_string_intern.html