黑马程序员技术交流社区

标题: 我对于字符串常量池的理解,希望对大家有些帮助 [打印本页]

作者: newLife    时间: 2014-11-3 15:30
标题: 我对于字符串常量池的理解,希望对大家有些帮助
class string
{
        public static void main(String[] args)
        {
                /*
                首先简单介绍下String 它不属于8种基本数据类型而是一个对象
                它一旦被确立就不会被改变;大家都知道一个对象的默认值为null,
                同样String默认也为null,例如 :String str=null。但String又有一个特性就是空,
                例如String str="";String str=new String();String str=new String("");
                在了解常量池之前先明确equals 和==的区别:
                在String中重写了Object中的equals方法比较的内容为相同的字符顺序
                而==比较的是内存地址是否相同
                什么是常量池:常量池是指在编译期间就确定,并保存在字节码文件中的一些数据。
                (它包括类,方法,借口等其中的常量,也包含字符串常量)
                //下面举例说明常量池
                */
                //1,下面创建了一些字符串常量
                String s="ab";
                String s1="ab";
                String s2="a"+"b";
                System.out.println(s==s1);//返回结果为true
                System.out.println(s==s2);//返回结果为true
                /*        那么为什么都是true呢,分析下原因;
                如上面的操作创建一个字符串会在编译期间就会被解析成一个字符串常量,
                并且保存在字符串常量池中。
                第一步:String s="ab";在编译期间就被解析保存在字符串常量池中
                第二步:String s1="ab";在编译期间也被解析成一个字符串常量,而常量池中有了"ab"
                所以s1也是常量池中“ab”的一个引用
                第三步:String s2="a"+"b";对于字符串“+”的连接,在编译期间JVM就会对"a"+"b"解析成连接
                后的值也就是“ab”,所以s2也也是常量池中"ab"的一个引用
                因此结果:它们的地址 都一样所以为true
                */
                //2,下面讲下直接赋值和new出来的区别
                String s="ab";
                String s1=new String("ab");
                String s2="a"+new String("b");
                System.out.println(s==s1);//结果返回false
                System.out.println(s==s2);//结果返回false
                /*分析如下
                第一步:String s="ab";它会在编译期间就被JVM解析并保存在字符串常量池中s为“ab”的引用
                第二步:String s1=new String("ab");因为new        String();出来的字符串不是常量,在编译期间它不会被确定
                因此不会保存在常量池中,而在运行期间被解析,在堆内存中创建一个字符串实例,它有自己的新地址
                第三步:String s2="a"+new String("b");上面说过,有+连接的地方在编译期间会被解析成一个连接后的字符串
                但是在此例中+的后半部分并不能在编译期间被解析,因此它也是在运行时期创建一个新的实例,
                有自己的地址
                */
               
                //3,原语String的intern()方法的介绍
                /*这里有一个知识点就是,常量池在会在运行时被虚拟机装载,并且可以扩充
                而intern()方法就是扩充字符串常量池的一个方法;
                当String 的实例s 调用intern()方法时会查看字符串常量池中是否有这个字符串常量,
                如果有则返回这个字符串常量的引用,没有将会在字符串常量池中添加一个s的字符串常量;
                并返回在常量池中的字符串引用,因此地址会变
                */
                String s="ab";
                String s1=new String("ab");
                String  s2=new String("ab");
                //这里为什么都是false大家应该都明白了,因为它们的地址都不同
                System.out.println(s==s1);//返回false
                System.out.println(s==s2);//返回false
                System.out.println(s1==s2);//返回fase
                //下面通过s1调用intern()方法
                s1.intern();//注意这个方法的介绍,并没有将返回后的引用再次赋值给s1,只是调用了一下
                s2=s2.intern();
                System.out.println(s==s1);//返回false
                System.out.println(s==s2);//返回true
                /*
                第一步:s1调用了intern()方法,查看常量池中是否存在“ab”,结果存在应该返回在字符串常量池中的引用
                但在这一步中我们并没有把这个引用赋值给s1因此s1还是堆内存中的引用,因此地址不同返回false
                第二步:s2调用了intern()方法,重复上一步的步骤,将常量池中的引用返回给了s2因此s2的引用指向了
                字符串常量池中的地址,因此返回了true
                通过这个例子也可以看到:在调用intern()方法时,并不是把在堆内存中的地址赋给了常量池中的地址
                还有就是对于String s="ab";String s1="a";String s2=s1+"b";这个例子来说跟new String()那个例子类似,
                不能在编译期间就确定,而是在运行时期赋予新的地址值
                这些只是我的理解,有错误的地方请大家指正,希望大家能看的明白!!
                祝大家学的愉快!!!
                */

        }
}



作者: 暮色醉玄阳    时间: 2014-11-3 18:08
学习了:lol




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2