面试常考题—Java常量池

常量池(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放在栈内存上,其他都放在堆内存上
	}

猜你喜欢

转载自blog.csdn.net/weixin_44736475/article/details/105645734