美文网首页java程序员
Java基础(四) | 形影不离的String字符串

Java基础(四) | 形影不离的String字符串

作者: 采风JS | 来源:发表于2017-06-23 23:59 被阅读227次

    字符串,一个深受折磨的朋友。它并不是基本数据类型,而是一种对象。关于此对象,常涉及到比较、访问、修改操作,是程序员编码的基本功。今天,将String进行深入剖析,做一个合格的蓝颜知己。

    1. " "、null和new String()的区别

    String s1 = null; 
    // 未分配内存,未创建引用,未初始化
    String s2 = " "; 
    String s3 = new String();
    // 完成初始化,分配内存,创建引用,但其值为空
    

    2. 字符串池

    创建字符串对象时,在字符串池中寻找具有相同字面值的对象,如果存在,则返回该对象的引用;如果不存在,则创建对象置于字符串池中,并且返回新创建对象的引用;

    字符串池的存在,减少内存开销,所以推荐使用非new的方式,使用String s = "bat"的方式;

    3. String、StringBuffer和StringBuilder

    • 三者区别
      String为不可变的字符串常量,而StringBuffer和StringBuilder为可变的字符串变量;
      String和StringBuffer为线程安全的,而StringBuilder为线程不安全的;
      针对String的修改操作会产生新的对象,而后两者只是在原有对象上改变,并不产生新的对象;

    • 应用场景
      字符串常量和少量字符串操作时,使用String类;
      在频繁字符串修改(替换、拼接和添加)时,比如Http参数解析、封装等,如果为多线程操作,使用StringBuffer,否则使用StringBuilder;

    4. String真是不可变对象吗?

    可以优先考虑一下这篇博客:Java中的String为什么是可变的?

    // String类的源码,jdk1.8
    private final char value[]; // String类可以看作是对不可变数组的封装
    private int hash; 
    // 基于反射改变String
        public static void main(String[] args) throws Exception{
            String name = "Xi Dian";
            Field value = String.class.getDeclaredField("value");
            value.setAccessible(true);
            char[] c = (char[]) value.get(name);
            c[2] = '_';
            System.out.println(name); // 打印结果为: Xi_Dian
        }
    

    5. 深入理解拼接操作

    • "+"操作符
    // 编译器对"+"操作符进行优化,下面两者等效
    str += "b";
    str = new StringBuilder().append("b").toString();
    
    • concat()方法
    // jdk1.8源码 concat方法
        public String concat(String str) {
            int otherLen = str.length();
            if (otherLen == 0) {
                return this;
            }
            // 此处的len为原字符串的长度
            int len = value.length;
            char buf[] = Arrays.copyOf(value, len + otherLen);
            // str将从0到自身length长度拷贝到buf中从len开始之后的位置
            str.getChars(buf, len);
            // 新建字符串
            return new String(buf, true);
        }
        void getChars(char dst[], int dstBegin) {
            System.arraycopy(value, 0, dst, dstBegin, value.length);
        }
    
    • append()方法
    // jdk1.8的源码 append()方法
        public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
            if (srcBegin < 0) {
                throw new StringIndexOutOfBoundsException(srcBegin);
            }
            if (srcEnd > value.length) {
                throw new StringIndexOutOfBoundsException(srcEnd);
            }
            if (srcBegin > srcEnd) {
                throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
            }
            System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
        }
    
        public AbstractStringBuilder append(String str) {
            if (str == null)
                return appendNull();
            int len = str.length();
            ensureCapacityInternal(count + len);
            // 从value的count索引开始,逐个添加str字符数组
            str.getChars(0, len, value, count);
            count += len;
            // 并不产生新的对象
            return this;
        }
    

    相关文章

      网友评论

        本文标题:Java基础(四) | 形影不离的String字符串

        本文链接:https://www.haomeiwen.com/subject/ypjhcxtx.html