zoukankan      html  css  js  c++  java
  • String,StringBuffer和StringBuilder

      java 基础中字符串用到最多的就是String,StringBuffer和StringBuilder,这三个也是面试中最常问到的,三者之间的异同,其实实际工作中,我们大致知道使用场景,但是要用理论话的语言去总结,总是比较麻烦。

    1.String

    1.1继承实现关系

    1.2 源码分析

     1> final 修饰的类无法被继承

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence 
    

    2> String的数据存放在final修饰的char数组中,所以String对象初始化之后值不能改

    /** The value is used for character storage. */
        private final char value[];
    

    3>String 值比较,总共两种方式,一种是继承了Comparable接口,实现compareTo()方法通过逐个字符串比较;

    另一种方法是,compareToIgnoreCase() 方法,通过静态成员类,实现Comparator方法,逐个char变大写比较,变小写比较;

     public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                             = new CaseInsensitiveComparator();
        private static class CaseInsensitiveComparator
                implements Comparator<String>, java.io.Serializable {
    //。。。。。。
    
    if (c1 != c2) {
        c1 = Character.toUpperCase(c1);
        c2 = Character.toUpperCase(c2);
        if (c1 != c2) {
            c1 = Character.toLowerCase(c1);
            c2 = Character.toLowerCase(c2);
            if (c1 != c2) {
                // No overflow because of numeric promotion
                return c1 - c2;
            }
        }
    }
    //。。。。。
    }

     

     

    4>字符串之间的关联,String提供了静态的方法,可以将多个字符串通过delimiter进行拼接;

    public static String join(CharSequence delimiter, CharSequence... elements) {
    }

    5>字符串的trim()方法,对字符串双端去空

     public String trim() {
            int len = value.length;
            int st = 0;
            char[] val = value;    /* avoid getfield opcode */
    
            while ((st < len) && (val[st] <= ' ')) {
                st++;
            }
            while ((st < len) && (val[len - 1] <= ' ')) {
                len--;
            }
            return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
        }
    

     

    2.AbstractStringBuilder

    2.1 继承实现关系  

     2.2源码分析

    1>初始长度设置,通过构造方法:数据存储在非fianl的char数组中,通过构造函数传参初始化;

      AbstractStringBuilder(int capacity) {
            value = new char[capacity];
        }
    

    2>.在append的时候,char[]数组进行扩容,一般是现有值长度的2倍+2

     public AbstractStringBuilder append(String str) {
            if (str == null)
                return appendNull();
            int len = str.length();
            ensureCapacityInternal(count + len);//已有长度+拼接字符串长度 为最小的容量
            str.getChars(0, len, value, count);
            count += len;
            return this;
        }
    
    private void ensureCapacityInternal(int minimumCapacity) {
            // overflow-conscious code
            if (minimumCapacity - value.length > 0) {//最小长度大于现有长度时,进行扩容
                value = Arrays.copyOf(value,
                        newCapacity(minimumCapacity));//复制生成新的char[]数组
            }
        }
    private int newCapacity(int minCapacity) {
            // overflow-conscious code
            int newCapacity = (value.length << 1) + 2;//容量编程 现有长度的2倍+2
            if (newCapacity - minCapacity < 0) { //扩容后还是小于最小长度时,将最小长度赋值给扩容长度
                newCapacity = minCapacity;
            }
            return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
                ? hugeCapacity(minCapacity)
                : newCapacity;
        }
    

    3.StringBuilder

    1.源码分析

    1>  final修饰的类,不可以继承

    public final class StringBuilder
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence
    

    2> 默认初始长度为16

    public StringBuilder() {
            super(16);
        }
    public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }

    3>转成字符串toString()方法是生成新的String对象

      @Override
        public String toString() {
            // Create a copy, don't share the array
            return new String(value, 0, count);
        }

    4.StringBuffer

    1.源码分析

    1> final修饰不可继承

     public final class StringBuffer

    2> toString缓存数据;

      1.通过一个transient修饰的字段toStringCache,进行转字符串存储;

      2.在每个值改变的操作将toStringCache设置为空;

      3.在toString()方法中,如果toStringCache为空,就copy新的char[]数组赋值给toStringCache ;

      4.如果StringBuffer中的数值没变动,调用toString方法的时候,直接调用toStringCache就可以了;

    private transient char[] toStringCache;
    @Override
    public synchronized StringBuffer append(long lng) {
       toStringCache = null;
       super.append(lng);
       return this;
    }
    @Override
    public synchronized String toString() {
       if (toStringCache == null) {
          toStringCache = Arrays.copyOfRange(value, 0, count);
       }
       return new String(toStringCache, true);
    }
    

      

    通过上面的可以知道,如下:

    相同点:

      1.都是final类,不可以继承;

      2.内部存取数据的都是char数组;

      3.都实现了CharSequeue,可以对字符串进行相关操作;

    不同点:

      1.String 和StringBuilder,StringBuffer的区别:

        - 1. String的值final 数组,赋值后不可改变;StringBuilder,StringBuffer 非final  char数组,初始化后可以改变值;

        - 2. String的字符拼接,每拼接一次,相当于生成一个新的字符串;StringBuilder,StringBuffer通过给内部的char数组扩容,不用生成新的对象,效率更高;

        - 3. char数组初始长度都是16 ;

      2.StringBuilder 和 StringBuffer 之间的区别:

        - 1. StringBuffer的所有操作都加synchorinized,因此是线程安全的;

        - 2. StringBuffer的toString方法,有缓存,多次toString效率更高;

        - 3.StringBuilder 效率更高,但是线程不安全;

     

    常见问题:

     1.自己写一个String,或StringBuilder类可以替换原有的JDK的String么?

        答:这个问题其实和String,StringBuilder没关系了,而涉及到的是JVM类加载中,双亲委派模型;

       双亲委派模型,是类加载器接收到当前类的加载请求,并不会直接去加载,而是逐级向父加载器发送请求,当父加载器没有相关的类,当前子加载器才自行加载;

      

     

     

      

      

      

  • 相关阅读:
    #RunJS# 最少代码的瀑布流实现
    浏览器“Web Freer”,直接上twitter、facebook等国外的网站,附带去掉广告的方法。
    fixed固定块背景,滚动的时候却换背景
    成为一个顶级设计师的八大秘诀
    Font Awesome设计原理分析
    IE6PNG透明解决办法(2)js
    有趣的反汇编
    我这个用notepad的小可怜虫..
    自修改代码(SMC)技术学习
    lua绑定C++对象学习
  • 原文地址:https://www.cnblogs.com/perferect/p/12879628.html
Copyright © 2011-2022 走看看