JAVA 字符串详解

JAVA 字符串详解,第1张

字符串创建有两种基本形式:

1、直接赋值:String s1 = "ab";

此 *** 作只会在字符串常量池创建一个“ab"字符串

2、用new String来创建一个字符串

此时分两种情况:

(1)字符串常量池中已经有和这个将要创建的字符串的字面量相等(.equal()返回true)的字符串,则只在堆中生成一个字符串对象。

String s1  = "ab";

String s2  = new String(“ab”);

两次ldc都是#2对应的字符串,即两次创建只在常量池中生成一个“ab”。

(2)字符串常量池中没有和这个将要创建的字符串的字面量相等的字符串:

此时会生成两个字符串对象,一个在堆中,一个在常量池。

(在此之前ldc索引只到16,而这里变成17说明常量池中也生成了一个字符串)。

3、字符串拼接

分三种情况:

(1)String s10 = "abc" + "d";

直接用字面量拼接的话,只会在常量池中生成一个字符串对象,且是拼完后的结果,拼之前的两个字符串不会在常量池中创建。

(2)String s4 = new String("ad") + new String("c");

总共创建了5个字符串对象,“ad“和”c”分别在堆中和在常量池中创建对象。但拼完的“adc”只在堆中而不在常量池中。

(3)String s17 = new String("abcge") + "k";

生成四个字符串对象,“abcge”在堆中和字符串常量池中都创建,“k”只在常量池创建,拼完的“abcgek”只在堆中。

(4) String s18 = "ab";

String s19 = "cd";

String s20 =  s19 + s18;

此种形式s20只会在堆中创建一个对象”abcd".

与情况1对比:对于情况1,java是直接将两个字符串拼接后的字符串存入常量池,原因是在编译期,这个字符串的值就已经确定,因此java直接对其优化,将该字符串存入常量池;而对于情况4,引用类型只有在运行时才能确定,因此虽然s18,s19在常量池中存了“ab"和”cd",但由于拼接时没有直接使用字面量,而是通过引用进行拼接,那么此时就只会在堆中创建一个“abcd"。

如果将s18,s19变为常量,那么此时s20就会将”abcd“存入常量池:

final String s18 = "ab";

final String s19 = "cd";

String s20 =  s19 + s18;

String s21 = "ab" +”cd";

System.out.println(s20==s21);  //返回true

##########################################################################

字符串拼接的实现原理是(非情况(1)时):

(1)先new一个空的StringBuilder对象

(2)将两个子串通过StringBuilder的append方法存到StringBuilder中

(3)最后通过StringBuilder的toString方法返回一个拼接完的String.

#########################################################################

Intern方法:

分两种情况:

(1)若常量池中有和调用此方法的字符串对象字面量相等的字符串,则返回常量池中的字符串对象的引用。

此例中,“ab“已在常量池中,调用intern返回常量池中”ab“的引用,因此s3==s1返回true.

(2)若常量池中没有的话,就返回当前字符串的引用

此例中,由于拼接之后的字符串不会在常量池创建,因此调用intern方法将把这个字符串放入常量池,并返回该字符串的引用(并不是在常量池中创建了一个新的“adc”,只是把堆中“adc”的引用放到常量池中,依然指向堆中的”adc”),因此s7==s6返回true.

如果此时用赋值法:String s8 = "adc";则会直接返回堆中“adc“的引用。

Intern方法的描述中我们可以看到对上述过程的描述。

注意,当常量池中没有该对象时,是“this String object is added to the pool and a reference to this String object is returned”,这里的add其实只是把引用放到常量池中,而并没有将“adc”从堆中移动到常量池。

总结:

单个new会创建2个对象,一个在堆,一个在常量池。

N个new *** 作,然后拼接会生成2*N+1个对象,每个new生成两个,一个在堆一个在常量池,最后拼出来的生成一个在堆中。

直接赋值都只会在常量池中创建一个。

直接赋值 拼接new : 直接赋值在常量池中创一个,new在堆和常量池各创一个,最后拼接会在堆中创一个,总共4个。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/719917.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存