Java String浅析

1.java String的创建方式

string 对象主要有如下几种创建方法:
(1)直接使用引号“”创建。
(2)使用new String()创建。
(3)使用new String(“something”)创建或者其他一些重载构造函数创建
(4)使用重载的字符串操作符“+”创建。

对于所有的字符串对象,有两种存储方式:一、对象值存在于常量池中,对象引用直接指向常量池;二、对象值保存在堆内存中,对象引用指向堆内存;
下面就根据java生成的集中方式进行分析。

(1) 直接使用引号“”创建。

String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2); //输出true

在上面的语句中,首先申明一个string引用s1,它指向一个string常量对象”abc”,在这种方式中,编译器首先会在常量池中寻找是否有”abc”字符串存在,若不存在,则将常量”abc”添加到常量池中,然后将s1引用指向常量池中的”abc”,若存在则直接将引用指向其。由此可知s2则是直接指向常量池中的”abc”。可知在上面的语句中总共就生成了一个字符串对象”abc”。

(2)使用new String()创建

这种方式创建的String的对象没有赋值,只是在堆内存中开辟一个初始大小的空间,然后让String引用指向空间地址,没啥说的。

(3)使用new String(”something “)创建对象

若使用String s = new String(”something “)创建对象,则首先编译时会在常量池中寻找”something”是否存在,若不存在则将”something”存于常量池中,在运行的时候将”something”复制一份到new String的堆内存区,然后让引用s指向堆内存区。

(4)使用“+”生成字符串

首先考虑“+”两边都是编译时可知的字符串。

   String s = "a" + "b" + " c";   //String s = "abc';

在这种情况下会在编译的时候直接将“a” , “b”, “c” 组成成”abc” 然后将其存储于常量池中。由此看来这段代码也就相当于:String s = “abc”;

另外一种情况就是,若”+”连接的字符串中有字符串引用变量。

String a1 = "abc"
String a2 = "bcd"
String s1 = a1 + "d";    //String s1 = (new StringBuilder()).append(a1).append("d").toString();
String s2 = a1 + a2;     //String s2 = (new StringBuilder()).append(a1).append(a2).toString();

在语句String s1 = a1 + “d”;中,由于”d”为在编译时就已知的常量,所以在编译的时候,就会将其添加到常量池中(若有则不添加,若无则添加)。同时编译器也会对其进行优化,将其转换为String s1 = (new StringBuilder()).append(a1).append(“d”).toString(); 即通过StringBuilder 来优化。 而语句String s2 = a1 + a2; 由于其中不存在常量则只是将其优化为:String s2 = (new StringBuilder()).append(a1).append(a2).toString();

说到这里肯定有的会说:按这么说string+string 的性能跟直接用StringBuilder差太多啊,因为底层实现是用stringbuild来实现的, 为什么很多人会说string+string会增加额外的系统开销呢?这就要从两方面来说了。
1.首先在较早版本的编译器中不会有这种优化。
2.即使现在存在这种优化它也不是万能的。因为当你只是在程序中是使用一次String + String :String s1 = a1 + a2; 它将被优化为:String s1 = (new StringBuilder()).append(a1).append(“d”).toString();这跟主动有StringBuilder没有区别,即使没有这种优化,少量的使用”+”性能方面也没有太多影响。然而我们要记得书中说的是当我们需要大量对String对象使用”+”运算符的时候,请主动使用Stringbuilder对象。这句话在编译器有优化的情况下仍然是正确的。如下:

//在一个for循环中使用"+"
String str = "begin";
for(int i = 0; i < 1000; i ++){
    str = str + "a";  //编译器会自动优化为 str = (new StringBuilder()).append(str).append("a").toString(); 
}

由上面代码可知,再编译优化的情况下,整个过程下了str = str + “a”; 会产生1000个匿名StringBuilder对象,且toString也会生成1000个string对象。而如果我们主动使用StringBuilder对象时,我们只会产生一个StringBuilder对象,最后toString会生成一个String对象,这就减少了很多创建对象的开销。

总结:

1.只有在编译时就可以确定的字符串常量才会被添加到常量池中,且”a” + “b” + “c” 会直接被组合成“abc” 所以常量池中只会有”abc”而不会有”a” , “b” “c”。
2.当使用string 引用进行”+”运算时,编译器会将其优化为StringBuilder的操作
3.多次使用对String 引用进行”+”运算时,显性的通过StringBuilder的append来代替,可使程序性能更优。
4.对于多个确定的string对象直接相加,性能反而更高。如String str = “ab” + “bc” + “cd”; 性能优于String str = stringBuilder.append(“ab”).append(“bc”).append(“cd”); 因为在编译器中”ab” + “bc” + “cd” 会被计算出来直接代替为”abbccd” .

你可能感兴趣的:(java,String,+,StringBuil)