常量池(1)
首先看看下面这段代码,猜猜输出结果是什么?
public static void main(String[] args) {
Integer n1= 127;
Integer n2 = 127;
System.out.println(n1==n2);
Integer n3 = 128;
Integer n4 = 128;
System.out.println(n3==n4);
Integer n5 = new Integer(127);
System.out.println(n1==n5);
}
输出的三个结果分别是:true,false,false;
可能很多人会有疑惑,为什么是这样的结果呢?
请往下看!
常量池(2)
Java为了提高程序的性能,为很多基本类型的包装类和字符串都建立了常量池。
什么叫常量池呢?
通俗来讲,常量池的意思是将确定的值用一个东西框起来,需要用的话,大家都指向这个地方,即相同的值只存储一份,节省内存,共享访问。
基本类型的包装类
Boolean,Byte,Short,Integer,Long,Character,Float,Dounle。
取值范围
Boolean: true,false;
Byte:-128-127;
Character:0-127;
Short,Int,Long:-128-127;
注:Float,Double没有缓存(常量池)
来看看下面代码输出什么。
基本类型包装常量池缓存机制:
public static void main(String[] args) {
Boolean b1 = true;//true,false
Boolean b2 = true;
System.out.println(b1==b2);//true
Byte b3 = 127;//-128-127
Byte b4 = 127;
System.out.println(b3==b4);//true
Character c1 = 127;//\u0000-\u007f
Character c2 = 127;
System.out.println(c1==c2);//true
Short s1 = -128;//-128-127
Short s2 = -128;
System.out.println(s1==s2);//true
//Double和Float没有常量池,所有d1,d2为两个不同的对象,故输出为false
Double d1 = 0.5;
Double d2 = 0.5;
System.out.println(d1==d2);//false
}
字符串常量池缓存机制
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
String s3 = "ab"+"c";//"ab","c"都是常量,编译器将优化,下同
String s4 = "a"+"b"+"c";
//s1,s2,s3,s4都指向同一个abc,
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
System.out.println(s1==s4);//true
}
常量池(3)
基本类型的包装类和字符串有两种创建方式
1.常量式(字面量)赋值创建,放在栈内存,将被常量化。
如:Integer a = 10;
String s = "abc"
.......
2.new对象进行创建,存放在堆内存,不会常量化。
如:Integer a = new Ingeter(10)
String s = new String("abc")
.......
这两种创建方式导致创建的对象存放的位置不同。
栈内存读取速度快但容量小,堆内存读取速度慢但容量大。
new将根据构造函数来创建对象,Java认为这种对象比较庞大,占用内存大,所以将new创建的对象放在堆内存,而像固定形态的值(常量式),直接放在栈内存上,占用内存小。
最后来分析下面代码,进一步地理解常量池。
public static void main(String[] args) {
int i1 = 10;
Integer i2 = 10; // 自动装箱
System.out.println(i1 == i2); // true
// 自动拆箱,基本类型和包装类进行比较,包装类自动拆箱
Integer i3 = new Integer(10);
System.out.println(i1 == i3); // true
// i1为基本类型,i3自动拆箱,输出true
System.out.println(i2 == i3); // false
// 两个对象比较,比较是否都指向同一个地址
// i2是常量,存放再栈内存常量池中,is是new出的对象,放在堆内存中。
Integer i4 = new Integer(5);
Integer i5 = new Integer(5);
System.out.println(i4 == i5);// false i4 i5都没基本类型,new出来的,指向的地址肯定不一样
System.out.println(i1 == (i4 + i5)); // true
System.out.println(i2 == (i4 + i5)); // true
System.out.println(i3 == (i4 + i5)); // true
// i4+i5的操作将会使得i4,i5自动超拆箱为基本类型并运算为10
// 基础类型10和对象比较,将会使对象自动拆箱
Integer i6 = i4 + i5;// +操作使得i4,i5自动拆箱,得到10,因此i6==i2,等价于Integer i6=10
System.out.println(i1 == i6); // true
System.out.println(i2 == i6); // true
System.out.println(i3 == i6); // false
//字符串没有装箱拆箱操作
String s0 = "abcdef";
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1 == s2);// true,常量池
System.out.println(s1 == s3);// false,s1在栈内存,s3在堆内存
System.out.println(s3 == s4);// false,两个都是堆内存。
String s5 = s1 + "def";// 涉及到变量s1,故编译器不优化
String s6 = "abc" + "def";// 都是常量,编译器会自动化成abcdef;
String s7 = "abc" + new String("def");// 涉及到new对象,编译器不优化
System.out.println(s5 == s6);// false
System.out.println(s5 == s7);// false
System.out.println(s6 == s7);// false
System.out.println(s0 == s6);// true
//只有s0,s6放在栈内存上,其他都放在堆内存上
}