您的位置:首页 > 编程语言 > Java开发

java : String 与常量池

2016-03-15 19:58 459 查看

先上题目:

String s1 = "abc";
String s2 = "abc";
System.out.println("s1==s2:"+(s1==s2));//true ,因为指向的是常量池中同一对象。
System.out.println("s1.equals(s2):"+(s1.equals(s2)));//true
String s3 = "ab"+"c";
System.out.println("s1==s3"+(s1==s3));//true,java自动优化为abc字符串 String s3 = "abc";
String s4 = "ab";
/*这里使用的是StringBudiler类的append方法,最后返回的是一个新的String对象
s5 = s4+"c";//这是变量和常量的加法,涉及到Builder
StringBuilder sb = new StringBudiler(s4);
sb.append("c");
s5 = sb.toString(){
return new String(value,0,count);
}
*/
String s5 = s4+"c";
System.out.println("s1==s5:"+(s1==s5));//false
System.out.println("s1.equals(s5):"+s1.equals(s5));//false
System.out.println("s1.intern()==s5.intern():"+(s1.intern()==s5.intern()));//true, intern()方法是在常量池中寻找相同的变量。
final String s6 = "ab";
s5 = s6+"c";
System.out.println("s1==s5:"+(s1==s5));//true,final是一个常量,这是常量之间的拼接,不涉及到StringBuilder,
String s7 = "jin|tian|tian|qi|zhen|hao!";
String[] sArray = s7.split("[|]");//这里利用的是spilt()的方法,作用是分割字符串。
for(int i= 0;i<sArray.length;i++){
System.out.println(sArray[i]);
}


知识点:不懂可以看这个。

Java中字符串对象创建有两种形式,一种为字面量形式,如String str = “droid”;,另一种就是使用new这种标准的构造对象的方法,如String str = new String(“droid”);,这两种方式我们在代码编写时都经常使用,尤其是字面量的方式。然而这两种实现其实存在着一些性能和内存占用的差别。这一切都是源于JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池。

工作原理

当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。

举例说明

字面量创建形式

String str1 = "droid";


JVM检测这个字面量,这里我们认为没有内容为droid的对象存在。JVM通过字符串常量池查找不到内容为droid的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量str1。

如果接下来有这样一段代码

String str2 = "droid";


同样JVM还是要检测这个字面量,JVM通过查找字符串常量池,发现内容为”droid”字符串对象存在,于是将已经存在的字符串对象的引用返回给变量str2。注意这里不会重新创建新的字符串对象。

验证是否为str1和str2是否指向同一对象,我们可以通过这段代码

System.out.println(str1 == str2);


结果为true。

可以参看这个

http://www.jb51.net/article/59935.htm

http://developer.51cto.com/art/201106/266454.htm

再来一个

说到java中堆、栈和常量池,首先还是看看他们各自存放的数据类型吧!

堆:存放所有new出来的对象;栈:存放基本类型的变量数据和对象的应用,对象(new出来的对象)本身并不存在栈中,而是存放在堆中或者常量池中(字符串常量对象存放在常量池中);常量池:存放基本类型常量和字符串常量。

对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。

而对于字符串来说,其对象的引用都是存储在栈中的,如果是编译期已经创建好(即指用双引号定义的)的就存储在常量池中,如果是运行期(new出来的对象)则存储在堆中。对于equals相等的字符串,在常量池中是只有一份的,在堆中则有多份。

举个例子吧!

String str1=”abc”;

String str2=”abc”;

String str3=”abc”;

String str4=new String(“abc”);

String str5=new String(“abc”);



**对于浅蓝色箭头,通过new操作产生一个字符串(“abc”)时,会先去常量池中查找是否有“abc”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此“abc”对象的拷贝对象,所以,对于String str=new String(“abc”),如果常量池中原来没有”abc”则产生两个对象,否则产生一个对象。

而对于基础类型的变量和常量,变量和引用存储在栈中,常量存储在常量池中。例如:**





对于成员变量和局部变量来说,成员变量是方法外部,类得内部定义的变量。局部变量就是方法或语句块内部定义的变量,注意,局部变量必须初始化。

局部变量(形式参数)的数据存于栈内存中,并且它(局部变量)随方法的消失而消失。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: