Java字符串

参考String内存机制管理

VM运行的时候,将内存分为两个部分,一部分是,一部分是。堆中存放的是创建对象,而栈中存放的则是方法调用过程中的局部变量或引用。在设计JAVA字符串对象内存实现的时候,在堆中又开辟了一块很小的内存,称之为字符串常量池,专门用来存放特定的字符串对象的。

Java中的new关键字在运行的时候才执行,编译只是检查语法,运行时才真正装入内存。

字符串常量

常量池(constant pool):在编译期被确定,并被保存在已编译的.class文件中的一些数据,它包括了关于类、方法、接口等中的常量,也包括字符串常量。

常量字符串池(pool)

字符串常量

如下特性:

  • 字符串必须会用双引号括起来。(不同于new String(string)构造的字符串)
  • 字符串的字符使用Unicode国际统一编码,一个字符占两个字节
  • String是一个final类,代表不可变的字符序列。
  • 字符串是不可变(immutable)的。一个字符串对象一旦被赋值,其内容就是固定不可变的。

String str = "Just";
str = "Justin";

上述程序,前一句是创建一个String对象,后一句是改变变量的指向,整个过程如下图所示。我们可知,“Just”的内容并没有改变,改变的只是变量str的指向,它指向了内存中另一个字符串对象。


对于可以共享的字符串对象,会现在字符串池中查找是否有相同的String内容,例如下代码:

String s0 = "kvill";
String s1 = "kvill";
String s2 = "kv" + "ill";

System.out.println(s0 == s1);
System.out.println(s0 == s2);

输出结果为:true   true

结果解析:当直接在程序中使用双引号创建字符串对象时,该字符串就被存储于字符串常量池中,而对于s1在创建之前会先检查字符串常量池中是否已经存在“kvill”,如果已经存在,则无须创建,直接指向该字符串即可。

Java会确保一个字符串常量只有一个拷贝。s0和s1都是字符串常量,在编译时期就被确定,两个变量都是指向同一引用,故s0==s1为true;而“kv”和“ill”也都是字符串常量,当一个字符串由多个字符串常量拼接而成时,其肯定也是字符串常量,所以s2在编译期就被解析成一个字符串常量,同样指向kvill,故s0==s1==s2。


用new String()创建的字符串不是常量,不能在编译期确定,故new String()创建的字符串不放入常量池,他们有自己的地址空间

String s0= "kvill";
String s1=new String("kvill");
String s2= "kv" + new String("ill");

System.out.println( s0==s1 );
System.out.println( s0==s2 );
System.out.println( s1==s2 );
输出结果:false   false  false

存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。

String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,相同与否由equals()方法决定,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用。

String str1 = "fly";
String str2 = "weight";
String str3 = "flyweight";
String str4 = null;
		
str4 = str1 + str2;
System.out.println("str3=?str4   " + (str3 == str4));
		
String str5 = "fly" + "weight";
System.out.println("str4=?str5   " + (str4 == str5));
		
str4 = (str1 + str2).intern();
System.out.println("str3=?str4   " + (str3 == str4));
System.out.println("str4=?str5   " + (str4 == str5));

输出结果:str3=?str4   false                 str4=?str5   false                   str3=?str4   true                   str4=?str5   true

结果解析:str1,str2,str3,str4,str5对应的内存存储样式如下图所示上部分所示,执行程序后字符串常量内存储样式如下部分所示。可以看出str3,str4,str5所指向的地址并不一样,故str3!=str4!=str5。当执行语句str4 = (str1 + str2).intern();时,会先在字符串常量池中寻找值为“flyweight”的地址,如果找到就将str4变量指向这个地址,如果没有找到就创建一个字符串常量并将其加入到常量池中,此处已经有这个值,所以str4变量直接指向这个地址。也就是说str3,str4,str5都指向同一个地址,三个引用指向同一个字符串对象。


关于equals()和==

这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。


关于String是不可变的

大家只要知道String的实例一旦生成就不会再改变了,比如说:String str=”kv”+”ill”+” “+”ans”;就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和” “ 生成 ”kvill “存在内存中,最后又和生成了”kvill ans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量,这也就是为什么建议用StringBuffer的原因了,因为StringBuffer是可改变的。


对于引用数据类型:引用数据类型数据.toString();因public String toString() 是类Object的一个方法,而java中其他类都是类Object的子类,所以所有的java类均会含有成员方法toString.在调用Syetem,out.println或者Syetem.out.print时,如果他们的参数是非字符串类型的数据,则一般将自动调用toString方法将其转换成字符串,然后输出。


两者是不一样的: 
1、String s="java"; 这里产生得到一个字符串常量。系统首先会去“常量池”寻找,看是否有“java”常量存在,如果有那么就将这个常量“java”赋给s,如果没有则系统在常量池里创建“java”,并将其给s。

2、String s = new String("java"); 意思是根据常量“java”创建一个字符串的对象,如此他首先会执行1中的操作,然后根据常量“java”在堆中创建对象,并为其分配内存。

参考文章: http://blog.csdn.net/vebasan/article/details/5271063

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值