java中的字符串到底是在方法区的常量池里还是new出来的对象里
Posted 稚枭天卓
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中的字符串到底是在方法区的常量池里还是new出来的对象里相关的知识,希望对你有一定的参考价值。
String实质是字符数组,两个特点:1、该类不可被继承;2、不可变性(immutable)
例如 String s1 = new String("myString");
和 String s1 = "myString";
第一种方式通过关键字new定义过程:在程序编译期,编译程序先去字符串常量池检查,是否存在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”;如果存在的话,则不用重新开辟空间,保证常量池中只有一个“myString”常量,节省内存空间。然后在内存堆中开辟一块空间存放new出来的String实例,在栈中开辟一块空间,命名为“s1”,存放的值为堆中String实例的内存地址,这个过程就是将引用s1指向new出来的String实例
第二种方式直接定义过程:在程序编译期,编译程序先去字符串常量池检查,是否存在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”;如果存在的话,则不用重新开辟空间。然后在栈中开辟一块空间,命名为“s1”,存放的值为常量池中“myString”的内存地址
转载自:https://zhidao.baidu.com/question/1431032825282549579.html
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
就速度来说,有如下关系:
寄存器 > 栈 >堆 >其他
这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。
对于字符串:
其对象的引用都是存储在栈中的,
如果是编译期已经创建好(即直接用双引号定义的)的就存储在常量池中,
如果是运行期(即new出来的)才能确定的就存储在堆中。
对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
如以下代码:
Java代码
String s1 = "china";
String s2 = "china";
String s3 = "china";
String ss1 = new String("china");
String ss2 = new String("china");
String ss3 = new String("china");
对于通过 new 产生一个字符串(假设为 ”china” )时,会先去常量池中查找是否已经有了 ”china” 对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此 ”china” 对象的拷贝对象。并把ss1指向堆中的地址。(在常量池中创建目的是为了提升字符串的访问效率)
再例子:
-
String s5 = new String("Hello"); //先在常量池中创建,再在堆中创建,返回的数值s5是堆中的地址
-
String s6 = s5.intern(); //返回的数值s6 ,是常量池中的地址
-
String s10 = "Hello"; //返回的数值s10,是常量池中的地址
-
System.out.println(s5 == s6); //输出false
-
System.out.println(s6 == s10); //输出true
这也就是有道面试题:
String s = new String(“xyz”); 产生几个对象?一个或两个,如果常量池中原来没有 ”xyz”, 就是两个。
对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。
转载自:https://blog.csdn.net/u012031380/article/details/54981472
以上是关于java中的字符串到底是在方法区的常量池里还是new出来的对象里的主要内容,如果未能解决你的问题,请参考以下文章