java基础(八)-----java中的常量池技术(底层)

先用一个问题引入常量池技术。

public class Test2 {

	public static void main(String[] args) {
		
		String s1="Hello Java";
		String s2="Hello Java";
		String s3=new String("Hello Java");
		System.out.println(s1==s2);//①
		System.out.println(s3==s2);//②

	}

}

问:①处的结果是多少?②处的结果是多少?很多初学者被这个问题弄的一头雾水。在java中像这样的问题还有其他的,比如说int与Integer(后面会提到这个)。这些都跟java的常量池有关。

什么是常量池?

常量池说白了就是一块内存区域,这块内存会对一些对象进行缓存,在需要的时候直接将其地址复制给变量,以达到加快效率,节省空间的作用。不仅String类具有常量池技术,而且大部分基本数据类型的包装类(Integer,long,short,byte,Character,Boolean)都实现了包装类。

常量池有什么作用?

常量池将一个类中的字符或者基本数据类型放入缓冲区(各自的常量池)中,如果程序后来想再创建此类对象,则可以直接生成,不需要new一个,这样可以节省时间和空间。

一:字符串常量池

接下来,我将常量池分成两部分,一部分是常见的String的常量池,叫做字符串常量池。这个常量池会存储类中已经初始化的字符串。举个例子:定义一个hello的字符串String  s  = “hello”;,虚拟机的工作原理是:首先在字符串常量池中寻找有没有“hello”,如果找到了,就将此字符串的地址赋值给s,如果没有找到,就会创建一个(new一个)新的字符串,当程序想创建第二个字符串“hello”的时候,就会直接将此地址赋值给新的变量。所以上面的程序①处输出true。

如果 程序是使用new来创建一个字符串的时候,会直接在堆内存中创建一个字符串对象。所以程序②处输出false。

总结:①当两个字符串没有通过new来创建的话,只要它们的值相同,那么它们进行相等运算(==)时返回true。

   ②当两个字符串都是使用new来创建的话,进行上述操作,都会返回false,因为它们不是同一个对象,也就不在同一个地址。示例代码:

public class Test4 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		String s2=new String("Java");
		String s3=new String("Java");
		System.out.println(s3==s2);//false
		
	}

}

   ③当一个字符串使用new来创建,另外一个没有使用new来创建的话,进行上述操作,都会返回false,也是因为它们不是同一个对象。示例代码:见开篇时得代码,程序②处。


接下来不得不提到一个知识点:

String类中有一个intern方法,当调用这个方法时,虚拟机会查找常量池中是否有此字符串,如果查到,就返回常量池中的字符串,如果没有,就返回此字符串。示例代码:

public class Test2 {

	public static void main(String[] args) {
		
		String s1="Hello Java";
		String s2="Hello Java";
		String s3=new String("Hello Java");
		//System.out.println(s1==s2);//①
		//System.out.println(s3==s2);//②
		
		System.out.println(s1==s3.intern());//③

	}

}
还是上面那个示例代码,只是最后一行有所改变,调用了s3的intern方法,此方法返回常量池中的Hello Java,所以程序③处放回true;

Interger类的常量池(-128--+127惹的祸)

废话不多说:直接上代码:

public class Test5 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int i1=128;
		Integer i2=128;
		System.out.println(i1==i2);//①自动拆箱true
		Integer i3=128;
		System.out.println(i2==i3);//②常量池技术的体现。-128--+127false
		Integer i4=127;
		Integer i5=127;
		System.out.println(i4==i5);//③常量池技术的体现true
		Integer i6=new Integer(128);
		Integer i7=new Integer(128);
		System.out.println(i6==i7);//④两个不同的对象的体现。false
	

	}

}

程序①,④处很容易得到该结论,根据②的结论,③处也应该和②一样啊,但是为什么是true呢?这里涉及到常量池技术。

原来,在使用Integer   i  = 一个int型的数字的时候,会自动进行装箱操作,调用了integer类的valueof方法,通过网上搜索和查看源代码,会发现,此方法内部使用了一个缓冲技术,也就是常量池,但是此常量池只会对—128到+127之间的int型数字进行插入缓存的操作。当后续代码中出现类似前面的把一个int型数据赋值给Integer的时候,会直接从缓存里面将该值赋给变量。程序③处为127,小于128,所以会把i4存入常量池,当定义i5的时候,会把127赋值给i5,所以他们是同一个数,程序②处根据上面可知,他们会调用new来创建两个Integer对象。所以是false。

结论:①两个都是new出来的话,他们进行“==”操作时,一定返回false;

   ②一个是new出来的,一个是int型的,进行“==”操作,一定放回true,此时会进行拆箱。

   ③ 一个new出来的,另一个是将int赋值的,肯定返回false,因为此时不会拆箱操作。

   ④两个都是讲int型的赋值给Integer的话,如果int值介于-128到+127时,放回true,其它的返回false。


其它的使用到常量池技术的:

public class Test6 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		Long  l1=127l;
		Long  l2=127l;
		System.out.println(l1==l2);//①true
		Long  l3=128l;
		Long  l4=128l;
		System.out.println(l3==l4);//②false  Long型与Short型与Integer一样介于-128---+127之间
		Boolean   b1=false;
		Boolean   b2=false;
		System.out.println(b1==b2);//③true  Boolean实现了常量池技术
		Float f1=1.0f;
		Float f2=1.0f;
		System.out.println(f1==f2);//④false  Float与Double型没有实现常量池技术。
		

	}

}

希望通过讲解,可以对常量池技术有一定的了解



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值