String、StringBuffer、StringBuilder对比

String、StringBuffer、StringBuilder对比

String类型
  1. 源码:
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
    ...
    ...
}

String具有不可变性,String底层使用的是final定义的char数组,不能被改变,String串被改变,会直接生成一个新的串。

  1. 测试代码:
    @Test
    public void test(){
        //字面量的定义方式 ,直接指向常量池
        String s1 = "abc";
        String s2 = "abc";

        System.out.println(s1 == s2);//比较s1和s2的地址值 true

        String str1 = new String("javaEE");
        String str2 = new String("javaEE");

        //new String()方式会在堆空间中开辟新的空间,并都去指向常量池中的"javaEE"
        System.out.println(str1 == str2); //比较的是地址值,false

        s1 = "hello"; //s1指向常量池中的hello
        System.out.println(s1 == s2);// false

        System.out.println(s1);//hello
        System.out.println(s2);//abc

        System.out.println("********拼接字符串*********");

        String s3 = "abc";
        s3 += "def";
        System.out.println(s3);//abcdef

        System.out.println("*******替换数据**********");

        String s4 = "abc";
        String s5 = s4.replace('a', 'm');

        String s6 = new String("abc");
        String b = s6.replace("b", "123");

        System.out.println(s4);//abc
        System.out.println(s5);//mbc
        System.out.println(s6);//abc
        System.out.println(b);//a123c
        /**
         * 地址值发生变化,不会改变原有的串
         * private final char value[]; String底层使用的是final定义的char数组,不能被改变,String串被改变,会直接生成一个新的串
         */
        System.out.println(s4 == s5);//比较s1和s2的地址值 false
        System.out.println(s6 == b);//false

        System.out.println("============= 字符串拼接 ================");
        String str3 = "java ";
        String str4 = "spring boot";
        String str5 = "java spring boot";
        //使用常量
        final String string1 = "java ";

        String str6 = str3 + "spring boot";
        String str7 = "java " + "spring boot";
        String str8 = new String("java ") + str4;
        String str9 = str3 + str4;
        String str10 = new String("java ") + "spring boot";

        //字符串拼接使用到变量时,会在堆空间中开辟新的空间,并指向常量池中的"java spring boot"
        System.out.println(str5 == str6); //false
        System.out.println(str5 == str8); //false
        System.out.println(str5 == str9); //false
        System.out.println(str5 == str10); //false

        System.out.println(str5 == str7); //true

        //string1是常量
        String string2 = string1 + "spring boot";
        System.out.println(str5 == string2); //true

        //i为变量
        int i = 1;
        String st1 = "1";
        String st2 = i + "";
        System.out.println(st1 == st2); //false


    }

    /**
     * String常用方法 前闭后开
     */
    @Test
    public void StringTest() {
        String str = "xm_1234_56";
        //返回第一次出现"_"的索引
        int index = str.indexOf("_"); //2
        int index2 = str.indexOf("_", 2);//包含起始索引在内
        int index3 = str.indexOf("_", 4);
        System.out.println("index2:" + index2 + "/index3:" + index3); //2 7

        int index4 = str.lastIndexOf("_", 2); //从索引为2往前找,包含起始索引在内
        System.out.println("lastIndexOf:" + index4); //2
        String substring = str.substring(0, index); //xm  前闭后开

        System.out.println(index + "/" + substring + "\n");

        boolean b = str.startsWith("3", 5); //true 包含起始索引在内
        boolean b1 = str.startsWith("3", 4); //false
        System.out.println(b + "/" + b1);

        boolean contains = str.contains("123");
        System.out.println("contains: " + contains); //true

        //字符与字符串
        String string= "中国加油 88888";
        char[] chars = string.toCharArray();
        String s = new String(chars);

        //字节与字符串 (编码解码不一致时,会出现中文乱码)
        byte[] bytes = string.getBytes(Charset.defaultCharset());

        String s1 = new String(bytes, Charset.defaultCharset());
        String gbk = new String(bytes, Charset.forName("GBK"));

        System.out.println("编码解码格式一致:" + s1 + "、不一致:" + gbk);


    }

    /**
     * 7种基本数据类型
     * 1、自动类型转换
     * byte 、char 、short --> int --> long --> float --> double
     * 当byte、char、short三种类型的变量做运算时,结果为int型,其他变量做运算,结果看大头
     * 小可以赋值给大(容量)
     * 2、强转
     * 使用()进行强转,可能出现精度丢失
     */
    @Test
    public void charTest(){

        char a = 'a';
        System.out.println(a); //a
        Long num = 12L;
        long b = a + num;
        System.out.println(b); //109
        System.out.println((char)b);  //m
        short num2 = 1;
        int i = a + num2;
        System.out.println(i);

        double c = a;
        System.out.println(c); //97.0

        char d = '0';
        System.out.println((int)d);//48

    }

StringBuffer、StringBuilder

  1. 源码:
 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;
    /**
     * Constructs a string buffer with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuffer() {
        super(16);
    }
    public StringBuffer(int capacity) {
        super(capacity);
    }
    ...
    ...
	@Override
    public synchronized StringBuffer append(CharSequence s) {
        toStringCache = null;
        super.append(s);
        return this;
    }
    //重写的方法AbstractStringBuilder抽象类的方法,通过super又调用了呗方法,所有StringBuffer/StringBuilder实际上是执行了相同父类中的方法。

}
	
//抽象父类中的append方法
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;
    
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        //将新数据str存放到底层char数组中
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        //数组容量不够用,minimumCapacity 为最少需要占用的容量大小
        if (minimumCapacity - value.length > 0) {
        	//创建一个新数组,把原数组的数据复制过来
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }
    
    //获取扩容之后容量大小
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        //扩容为原来的2倍+2
        int newCapacity = (value.length << 1) + 2;
        // 扩容为原来的2倍+2之后还不够,则使用最少需要占用的容量大小
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        //MAX_ARRAY_SIZE  = Integer.MAX_VALUE - 8;
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

    private int hugeCapacity(int minCapacity) {
    	//出现内存溢出问题
        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

}

推荐使用StringBuffer/StringBuilder时,根据实际需求指定capacity容量大小(使用有参构造),避免频繁的扩容。

  1. 测试代码:
public class StringBufferBuilderTest {

    /**
     * StringBuffer(线程安全,内部都是同步方法) 、StringBuilder(线程不安全) 都继承同一个抽象父类AbstractStringBuilder
     * 执行效率: StringBuilder > StringBuffer > String
     *
     * 默认底层创建了一个长度是16的char数组(无参构造方法)
     * 
     */
    @Test
    public void test(){
        // 
        //char[] value = new char[16];底层创建了一个长度是16的char数组。
        StringBuffer sb = new StringBuffer(); 
        System.out.println("被使用的长度:" + sb.length()); // 0
        System.out.println("容量:" + sb.capacity()); // 16
        sb.append('a');//value[0] = 'a';
        sb.append('b');//value[1] = 'b';
        System.out.println("被使用的长度:" + sb.length()); // 2
        System.out.println("容量:" + sb.capacity()); // 16

        StringBuffer sb1 = new StringBuffer("aaa"); //底层初始创建了容量是16 + "aaa".length() = 19 的char数组。
        System.out.println("被使用的长度:" + sb1.length()); // 3
        System.out.println("容量:" + sb1.capacity()); // 19
        sb1.append("111111111111111111111"); //长度为21
        /**
         *  扩容方法:ensureCapacityInternal();
         *  容量不足时,扩容为原来容量的2倍 + 2,并比较需要占用的容量大小和新扩容的容量大小,取大值作为新数组的容量,
         *  如果使用新容量还需要判断容量是否超出Integer.MAX_VALUE,会出现OOM,
         * 	将原数组中的元素复制到新的数组中,再将新数据添加到新数组中。
         */
        System.out.println("新容量:" + sb1.capacity());// 19*2 + 2 = 40
        System.out.println("被使用的长度:" + sb1.length()); // 24


        /**
         * 常用方法(左闭右开)
         */
        StringBuilder builder = new StringBuilder(64);
        builder.append("abcdef");
        builder.append(true);
        int tr = builder.indexOf("tr", 2);
        System.out.println("indexOf() : " + tr);

        //替换一个字符串
        builder.replace(1,3,"BC");
        System.out.println("replace():" + builder);
        //替换一个字符
        builder.setCharAt(3,'中');
        System.out.println("setCharAt() : " + builder);

        //删除一个字符deleteCharAt
        builder.deleteCharAt(3);
        System.out.println("删除一个字符deleteCharAt:" + builder);

        builder.insert(3,"中国人");
        System.out.println("插入一个字符串insert():" + builder);

        //遍历
        for (int i = 0; i < builder.length(); i++) {
            char c = builder.charAt(i);
            System.out.println(c);
        }

        System.out.println(builder.toString());
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值