zoukankan      html  css  js  c++  java
  • 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字符串对象
  • 相关阅读:
    springboot集成mockito与powermock
    不一样的go语言-玩转语法之二
    不一样的go语言-玩转语法之一
    不一样的go语言-athens源码概览
    不一样的go语言-athens私仓安装
    不一样的go语言-构建系统与构件系统
    不一样的go语言-error
    不一样的go语言-gopher
    jssip中文开发文档(完整版)
    echarts属性的设置(完整大全)
  • 原文地址:https://www.cnblogs.com/zhai1997/p/12423092.html
Copyright © 2011-2022 走看看