java字符串处理--String,StringBuffer,StringBuilder类

在java程序中,字符串的处理,是非常常见的。java中,字符串处理的类有,String,StringBuffer,StringBuilder类。下面简单总结下java程序里的字符串各种处理的区别。

String literal(字面量字符串)

字面量字符串(String literal)就是那些直接在代码文件里用双引号扩起来的字符串申明,比如String str=”abc”。当字面量字符串被创建的时候,JVM就会把”abc”这个字符串对象放到字符串常量池里。如果下次再”abc”这个字符串的引用,则直接使用常量池里的对象,而不是重新创建新的String对象。

public class TestStringLiteral {
    public static void main( String[] args ){
        String str1 = "hello";
        String str2 = "hello";
        System.out.println(str1 == str2);
        //true
        //字面量字符串不会被重复创建
    }
}

String类

String类是不可变(immutable)的。在java中,所有不可变对象都是线程安全的。所以,字符串是不能被两个线程同时使用的。字符串对象一旦被分配,就永远不会再被改变。所有针对String类做改变的操作,都是创建了一个新的字符串。而之前对象的内容,是不会被改变。

public class TestString {
    public static void main( String[] args ){
        String str1 = new String("hello");
        String str2 = str1;
        System.out.println(str1 == str2);
        //true
        str2 = str2.replace('h', 'H');
        //新建了一个新的String对象
        System.out.println(str1);
        //hello
        System.out.println(str2);
        //Hello
        System.out.println(str1 == str2);
        //false
    }
}

intern函数

使用new创建的String对象,是不会放到字符串常量池中的。如果想把new出来的String对象放到字符串常量池中,可以使用String提供的intern函数。intern函数会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。

public class TestIntern {
    public static void main( String[] args ){
        String str1 = new String("hello");
        String str2 = "hello";
        String str3 = str1.intern();

        System.out.println(str1 == str2);
        //false
        System.out.println(str2 == str3);
        //true
        //都指向常量池里的对象
    }
}

字符串常量池的好处,就是减少相同字符串的创建,节约内存。但字符串常量池里的所有字符串都是不会被GC回收的。

字符串常量池的基础就是上面介绍的String类是不可变的。

String几个小问题

1.如下代码,创建了几个String对象

String s = new String("abc")

A:创建了两个对象。第一个对象是”abc”字符串存储在常量池中,第二个对象在JAVA Heap中的 String 对象。正如上面TestIntern的例子代码里,str1和str2并没有指向同一个对象。

2.下面代码,创建了几个对象

String test = "a" + "b" + "c";

A:只创建了一个对象,在常量池中也只保存一个引用,即字符串abc。因为,JVM对初始化的连接操作字符串进行了优化。

StringBuilder

StringBuffer是可变的。StringBuffer被创建了之后,会在堆(heap)内存区new一块内存。StringBuffer的所有修改操作,都是直接改变heap区域内的值。同时,StringBuilder也是线程不安全的,如果有两个线程同时对StringBuilder对象进行修改,则会出问题。

public class TestStringBuilder {
    public static void main( String[] args ){
        StringBuilder strBuilder1 = new StringBuilder("hello");
        StringBuilder strBuilder2 = strBuilder1;
        System.out.println(strBuilder1 == strBuilder2);
        //true
        strBuilder1.append(" bye");
        System.out.println(strBuilder1);
        //hello bye
        //因为StringBuilder对象直接改变内存里值
        System.out.println(strBuilder2);
        //hello bye
        System.out.println(strBuilder1 == strBuilder2);
        //true
    }
}

StringBuffer

StringBuffer类和StringBuilder类一样,都是可变的,同时也拥有相同的函数接口。但与StringBuilder不同的是,StringBuffer是线程安全的。由于,每个操作都需要进行线程同步操作。所以,StringBuffer类会比StringBuilder类慢。除非有特殊需要,否则,最好是使用StringBuilder来代替StringBuffer。

字符串连接性能比较

public class StringTest {
    final static String TEST_STRING = "abcdefghijklmnopsdsdfsad";
    final static int LOOP_COUNT = 10000;
    static String useString(){
        String result = "";
        for (int i=0; ireturn result;
    }

    static String useStringBuilder(){
        StringBuilder builder = new StringBuilder();
        for (int i=0; ireturn builder.toString();
    }

    static String userStringBuffer(){
        StringBuffer buffer = new StringBuffer();
        for (int i=0; ireturn buffer.toString();
    }

    public static void main( String[] args ) {
        long begin = System.currentTimeMillis();
        useString();
        long strEnd = System.currentTimeMillis();
        useStringBuilder();
        long builderEnd = System.currentTimeMillis();
        userStringBuffer();
        long bufferEnd = System.currentTimeMillis();
        System.out.println("String time:"+ (strEnd - begin));
        System.out.println("StringBuilder time:" + (builderEnd - strEnd));
        System.out.println("StringBuffer time:" + (bufferEnd - builderEnd));
    }
}

上面程序,在我的机器上的输出结果为:

String time:2802
StringBuilder time:3
StringBuffer time:11

从上面的结果可以看到,String类比StringBuilder类的性能要差很多。所以,千万不能使用”+”进行String字符串的拼接操作,要优先使用StringBuilder的append操作。

你可能感兴趣的:(java)