javase(String、StringBuffer、StringBulider的区别)

1、存储空间

(1)String的对象一旦创建就不能改变(实质是一个被final修饰的字符数组),是一个常量,对String操作后会生成新的String,效率低且浪费空间。

  public  static  void main(String [] args){
        String string="jiayou!!";
        System.out.println(string);
        string="zhongguo"+"jiayou!!";
        System.out.println(string);
    }

 根据运行结果来看,string看似已经被修改了,但是实际上并没有被修改。刚开始创建一个string对象并赋值为“jiayou!!”,在第二次赋值的时候,又创建了一个新的对象,将值赋给新的对象,而原来的对象被JVM的垃圾回收机制回收掉了。

源码:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];//被final修饰

(2)StringBuffer和StringBulider的对象都是可以改变的(实质是可变长度的字符数组),节省了空间,效率较高。不能使用String"+"来拼接,避免产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。

    public  static  void main(String [] args){
        StringBuffer stringBuffer=new StringBuffer().append("wuhai").append("jiayou!!");
        System.out.println(stringBuffer.toString());
    }

这样的话JVM就不用频繁地创建和回收对象了,速度就会加快,也节省了空间,拼接字符串的时候不要使用String。

2、线程安全性

(1)线程安全:String、StringBuffer

StringBuffer中的很多方法带有synchronized关键字加了同步锁,保证了线程的安全性,但是StringBulider没有。所以,多线程的情况下必须使用StringBuffer。(在类里面定义成员变量,并且这个类的实例对象会在多线程环境下使用,那么最好用StringBuffer)

public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

(2)线程不安全:StringBulider

单线程的情况下使用(如果一个字符串变量是在方法里面定义,这种情况只可能有一个线程访问它,不存在不安全的因素了,则用 StringBuilder)

    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

3、执行效率:StringBulider最快,Stringbuffer次之,String最差

StringBulider线程不安全,速度最快;StringBuffer线程安全,速度稍慢;String线程安全,速度最慢。

4、版本

StringBuffer  老(1.0)

StringBulider  较新(1.5)

总结:

1、有没有哪种情况用“+”做字符串连接比调用StringBuffer 或 StringBuilder对象的append方法性能更好?

 如果连接后得到的字符串在静态存储区中是早已存在的,那么用"+"做字符串连接是优于StringBuffer / StringBuilder的append方法的(字符串在静态存储区中是早已存在的 ,会直接把对象的引用指向这个字符串,不会再开辟内存)。

2、程序题:

public class StringTest {
    public static void main(String args []){
        String string1="cun nuanhua kai";
        String string2=new String("cun nuanhua kai");
        String string3="cun nuan"+"hua kai";
        System.out.println(string1==string2);//f
        System.out.println(string1==string3);//t
        System.out.println(string2==string3);//f
        System.out.println(string1.equals(string2));//t
        System.out.println(string1.equals(string3));//t
        System.out.println(string1.intern()==string2.intern());//t
    }
}
false
true
false
true
true
true

(1)第一个主要考察对一个对象的引用直接赋值一个字符串与new String获得一个字符串的区别:

如果是直接赋值一个字符串的话,需要先在常量池中查找,如果没有的话会去开辟内存空间,把地址给栈指针。如果该字符串在常量池中已经存在了,那么直接将该字符串的地址赋给栈指针即可。

new String的话,是在堆内存中开辟内存并将指针赋给栈,与常量池不同的是,他不会去查找有没有相同的字符串,直接new一个对象。在这个过程中一共创建了两个对象一个是静态存储区的对象,一个是用new创建在堆上的对象

(2)第二个和第三个主要考察拼接的字符串是指向常量池还是堆内存:

编译时期能够确定字符串的值:

    public static void main(String args []){
        String string1="cun nuanhua kai";
        String string2= new String("cun nuanhua kai");
        String string3="cun nuan"+"hua kai";
        System.out.println(string1==string3);//t
        System.out.println(string2==string3);//f
    }

常量的值在编译的时候就确定了,string3也都是由常量拼接而成在编译时期也是确定的,此时,指向常量池中的字符串。

编译时期不能确定字符串的值:

public static void main(String args []){
        String string1="cunnuanhuakai";
        String string2= new String("cunnuanhuakai");
        String string3="cunnuan";
        String string4="huakai";
        String string5=string3+string4;
        System.out.println(string1==string5);//f
        System.out.println(string2==string5);//f
    }

s5由两个String变量相加得到,不能再编译时就确定下来,不能直接引用常量池中的对象,而是在堆内存中创建一个新的String对象(拼接后的字符串创建的对象)并由s5指向。

(3)第四个和第五个输出是对String类的equals()方法的考察:

因为String类已经对equals()方法进行了重写,它的功能由比较两个对象是否是同一个对象,转化为对象的值是否相等。

 (4)intern方法:https://www.cnblogs.com/zhai1997/p/12855383.html

3、String s = new String("abc"),创建了几个String类型的对象

分为两种情况:

  • 当字符串常量值中没有字符串abc的时候需要创建两个对象,一个是在字符串常量池中,另外一个在堆内存中并由对象的引用s指向它
  • 当字符串常量池中已经存在字符串abc的话,就不会在字符串常量池中创建对象了,只用在堆内存中创建对象即可。new方式创建字符串对象的时候,不管堆内存中有没有abc字符串对象,都会重新创建一个abc字符串对象
原文地址:https://www.cnblogs.com/zhai1997/p/12423092.html