java的常量池问题

来源:互联网 发布:excel2007办公软件 编辑:程序博客网 时间:2024/05/16 23:42

最近LZ在看一些博客的时候遇到一个问题,后来百度了才知道java有一个很重要的知识点,就是常量池问题。先看下面这个问题:

public class T 
{
public static void main(String[] args) 
{
testFinal();
}
public static void testFinal()
{
String s1 = "ab";
String s2 = "a";
String s4 = s2 + "b";
System.out.println(s2 + "   " + s4);
System.out.println(s1 == s4);
final String s3 = "a";
String s5 = s3 + "b";
System.out.println(s3 + "   " + s5);
System.out.println(s1 == s5);

}
}              

上述两个输出的结果分别是什么?

得到的结果是false和true。这是什么原因呢?主要就是这个常量池在起作用。首先得理解常量池技术

java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有就创建一个),则在需要重复创建相等变量时节省了很多时间。常量池其实就是一个内存空间,常量池存在于方法区中。

JVM的编译器将源程序编译成class文件后,会用一部分字节分类存储这些粗体代码。而这些字节我们成为常量池。其中包括了类、方法和接口等中的常量,也包括字符创常量,如String s = "java"这种。对于这种方式,在编译时,会被识别为同一字符串,自动优化成常量,所以如果有多个字符创"java"时候,则他们会引用自同一String对象。也就是说String s = "java" 其中"java"值在JAVA程序编译期就确定下来了的。(大家可以用UE编辑器或其它文本编辑工具在打开class文件后的字节码文件中看到这个java值)。这个java存在在常量池中。注意:常量池只存储文字字符串值,不存储符号引用。

而在运行时创建的字符串具有独立的内存地址,所以不引用自同一String对象.String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回一个引用,没有则添加自己的字符串进入常量池,注意:只是字符串部分。所以这时会存在2份拷贝,常量池的部分被String类私有并管理,自己的那份按对象生命周期继续使用。String s = new String("java");语句,到底创建了几个对象呢?  "java"本身就是常量池中的一个对象,而在运行时执行new String()时,将常量池中的对象复制一份放到堆中,并且把堆中的这个对象的引用交给s持有。所以这条语句就创建了2个String对象。

用new String()创建的字符串不是常量,不能在编译期就确定,所以new String()创建的字符串不放入常量池中,他们有自己的地址空间。String 对象(内存)的不变性机制会使修改String字符串时,产生大量的对象,因为每次改变字符串,都会生成一个新的String。 java 为了更有效的使用内存,常量池在编译期遇见String 字符串时,它会检查该池内是否已经存在相同的String 字符串,如果找到,就把新变量的引用指向现有的字符串对象,不创建任何新的String 常量对象,没找到再创建新的。所以对一个字符串对象的任何修改,都会产生一个新的字符串对象,原来的依然存在,等待垃圾回收。
String a = “test”;
String b = “test”;
String b = b+"java";
a,b同时指向常量池中的常量值"text",b=b+"java"之后,b原先指向一个常量,内容为"test”,通过对b进行+"java"操作后,b之前所指向的那个值没有改变,但此时b不指向原来那个变量值了,而指向了另一个String变量,内容为”text java“。原来那个变量还存在于内存之中,只是b这个变量不再指向它了。
 
 
八种基本类型的包装类和对象池  java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用常量池
Integer a = new Integer(128);
Integer b = new Integer(128);
这个时候再问你,输出结果是什么?你就知道是false了。如果把这个数换成127,再执行:
Integer a = 127;
Integer b = 127;
System.out.println(a == b);
结果就是:true
进行对象比较时最好还是使用equals,便于按照自己的目的进行控制。这里引出equals()和==,equals比较的是字符串字面值即比较内容,==比较引用。

0 0
原创粉丝点击