JAVA常用类库之String

1.String

str1指向的是常量池中的“abc”,str2指向的是堆内的String对象,这个String对象指向的才是常量池中的“abc”。

      String str1="abc";
      String str2=new String("abc");
      System.out.println(str1==str2);//false

String字符串的底层是字符数组

 private final char value[];

通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String

				 String str3="abc";
        byte[] arr = str3.getBytes("utf8");
        String str4=new String(arr, "utf8");
        System.out.println(str4);//abc

返回指定索引处的 char 值。

//底层源码
 if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
 return value[index];


System.out.println(str1.charAt(1));//b

按字典顺序比较两个字符串,从第一个字符开始比较它们的ASCII码值。

 public static void main(String[] args) throws UnsupportedEncodingException {
        String str1="abc";
        String str2="ABB";
        System.out.println(str1.compareTo(str2));//32
        String str3="abc";
        System.out.println(str1.compareTo(str3));//0
        System.out.println(str2.compareTo(str1));//-32
        String str4="abcd";
        System.out.println(str1.compareTo(str4));//-1
    }

//源码分析
public int compareTo(String anotherString) {
  			//1.获取字符数组或者说字符串的长度
        int len1 = value.length;
        int len2 = anotherString.value.length;
  			//2.取两个长度的最小值
        int lim = Math.min(len1, len2);
  			//3.将两个字符数组赋给新的字符数组
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
          	//4.对相同索引的字符进行比较,如果相等则进入下一个循环,否则返回ASCII差值
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
  			//5.如果进行比较的那些字符全部相等,那么返回数组长度的差值
        return len1 - len2;
    }

将指定字符串连接到此字符串的结尾。

public static void main(String[] args) throws UnsupportedEncodingException {
        String str1="abc";
        String s = str1.concat("def");
        System.out.println(s);//abcdef
    }

//源码分析
public String concat(String str) {
  			//1.获取字符串长度
        int otherLen = str.length();
  			//2.如果传入的字符串长度为0,直接返回当前字符串对象
        if (otherLen == 0) {
            return this;
        }
  			//3.将需要拼接的字符串以及传入的字符串复制到字符数组中
  			//public static native void arraycopy(Object src,  int  srcPos,
        //                                Object dest, int destPos,
        //                                int length);
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
  			//4.将字符数组转化为字符串并返回
        return new String(buf, true);
    }

当且仅当此字符串包含指定的 char 值序列时,返回 true

public static void main(String[] args) {
        String str="abc";
        System.out.println(str.contains("a"));//true
    }

//源码分析
public boolean contains(CharSequence s) {//CharSequence是一个接口,String类实现了该接口
        return indexOf(s.toString()) > -1;//通过返回的索引值来判断是否有该char值序列
    }

测试此字符串是否以指定的后缀结束。

public static void main(String[] args) {
       String s="abc";
        System.out.println(s.endsWith("bc"));//true
    }

//源码分析
 public boolean endsWith(String suffix) {
   			//调用startWith方法
        return startsWith(suffix, value.length - suffix.value.length);
    }

public boolean startsWith(String prefix, int toffset) {
  			
        char ta[] = value;
        int to = toffset;//toffset表示从什么位置开始比较
        char pa[] = prefix.value;
        int po = 0;
        int pc = prefix.value.length;
        // Note: toffset might be near -1>>>1.
  			//如果当前字符串对象长度小于后缀字符串长度,这里只针对endsWith分析,那么返回false
        if ((toffset < 0) || (toffset > value.length - pc)) {
            return false;
        }
        while (--pc >= 0) {//这一步是用于防止越界
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
    }

将此字符串与指定的对象比较。

 public static void main(String[] args) {
       String s="abc";
        System.out.println("abc".equals(s));//true
    }

//源码分析
 public boolean equals(Object anObject) {
        if (this == anObject) {//1.如果它们的地址相同,那么必然是同一个对象
            return true;
        }
        if (anObject instanceof String) {//2.如果参数对象是String的实例
            String anotherString = (String)anObject;//强转为String
            int n = value.length;
            if (n == anotherString.value.length) {//3.判断长度是否一样,不一样就不用比了
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])//只要有一个字符不一样就返回false
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

当且仅当 length()0 时返回 true

public static void main(String[] args) {
       String s="abc";
        System.out.println(s.isEmpty());//false
        String s1="";
        System.out.println(s1.isEmpty());//true
    }

返回指定字符在此字符串中最后一次出现处的索引。

public static void main(String[] args) {
       String s1="abccb";
        System.out.println(s1.lastIndexOf('b'));//4
    }

返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。

public static void main(String[] args) {
       String s1="abcda";
        System.out.println(s1.replace('a', 'e'));//ebcde
    }

//源码分析
public String replace(char oldChar, char newChar) {
  			//如果新字符不同于旧字符
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */
						//如果没有一个字符和oldchar一样,那就不用替换了
            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                  	//将字符数组进行复制
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                  	//等于oldChar则替换
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
       }
        return this;
    }

根据给定正则表达式的匹配拆分此字符串。

public static void main(String[] args) {
        String s="a,b,c,d,e";
        String[] split = s.split(",");
        for (String s1 : split) {
            System.out.println(s1);
        }
    }

返回一个新的字符串,它是此字符串的一个子字符串。

public static void main(String[] args) {
        String s1="abcde";
        System.out.println(s1.substring(1, 2));//b
    }

//源码分析
public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);//调用构造方法
    }

public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
  			//将第一参数的数组中的从offset-offset+count复制到当前创建的String对象的value(字符数组)中
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

将此字符串转换为一个新的字符数组。

public static void main(String[] args) {
        String s1="abcde";
        char[] arr = s1.toCharArray();
        for (char c : arr) {
            System.out.println(c);//a b c d e
        }
    }

//源码分析
public char[] toCharArray() {
        // Cannot use Arrays.copyOf because of class initialization order issues
        char result[] = new char[value.length];
        System.arraycopy(value, 0, result, 0, value.length);//将当前对象的value复制到另一个字符数组并返回
        return result;
    }

使用默认语言环境的规则将此 String 中的所有字符都转换为小写。

public static void main(String[] args) {
        String str="ABC";
        System.out.println(str.toLowerCase());//abc
    }

返回字符串的副本,忽略前导空白和尾部空白。

public static void main(String[] args) {
       String str=" ab c d ";
        String trim = str.trim();
        System.out.println(trim);//ab c d
        System.out.println(trim.length());//6
    }

正则表达式的简单使用

private static void method10() {
        String str=" ";
        String regex="\\W";//非单词字符
        System.out.println(str.matches(regex));//true
    }

    private static void method09() {
        String str="_";
        String regex="\\w";//单词字符:[a-zA-Z_0-9]
        System.out.println(str.matches(regex));//true
    }

    private static void method08() {
        String str="a";
        String regex="\\S";//非空白字符
        System.out.println(str.matches(regex));//true
    }
//空格、制表符、换行符、回车、换页垂直制表符和换行符称为 “空白来字符
    private static void method07() {
        String str=" ";
        String regex="\\s";//空白字符
        System.out.println(str.matches(regex));//true
    }

    private static void method06() {
        String str="a";
        String regex="\\D";//非数字[^0-9]
        System.out.println(str.matches(regex));//true
    }

    private static void method05() {
        String str="1";
        String regex="\\d";//数字:[0-9]
        System.out.println(str.matches(regex));//true
    }

    private static void method04() {
        String str="d";
        String regex=".";//任何字符(与行结束符可能匹配也可能不匹配)
        System.out.println(str.matches(regex));//true
    }

    private static void method03() {
        String str="a";
        String regex="[a-zA-Z]";//a 到 z 或 A 到 Z,两头的字母包括在内(范围)
        System.out.println(str.matches(regex));//true
    }

    private static void method02(String d, String s) {
        String str = d;
        String regex = s;//任何字符,除了 a、b 或 c(否定)
        System.out.println(str.matches(regex));
    }

    private static void method01() {
        method02("a", "[abc]");
    }
2.StringBuffer

一个带有缓冲区的可变字符串,实现了Charsequence接口,线程安全(内部方法加锁)。

/**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;//缓冲区,每次修改StringBuffer都会清理缓存。
-------------------------------------------------------
//构造
public StringBuffer(int capacity) {
        super(capacity);//调用父类有参构造
    }
//父类构造
AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

往StringBuffer追加

        StringBuffer sb=new StringBuffer("abc");
        StringBuffer def = sb.append("def");
        System.out.println(sb);//abcdef
        System.out.println(def);//abcdef
        System.out.println(sb==def);//true

//源码分析
 @Override
    public synchronized/*线程安全*/ StringBuffer append(String str) {
        toStringCache = null;//缓存区清空
        super.append(str);//调用父类append
        return this;
    }
//父类append
public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);//count是目前缓冲区内已有字符串的长度
        str.getChars(0, len, value, count);//将str加到value中
        count += len;//已有的字符串长度改变
        return this;
    }

/**
     * The count is the number of characters used.
     */
    int count;

//父类ensureCapacityInternal
private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {//如果已有字符串长度+即将添加字符串长度大于字符数组value长度
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));//value指向新数组
        }
    }

//父类newCapacity
private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;//<<左移运算符,相当于乘以2
        if (newCapacity - minCapacity < 0) {//如果新的容量还是小于minCapacity,那就直接把minCapacity赋给它
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)//返回新容量
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

返回当前容量

System.out.println(sb.capacity());//19  返回当前容量。

移除此序列的子字符串中的字符。

sb.delete(1, 2);
        System.out.println(sb);//acdef

//源码分析
 @Override
    public synchronized StringBuffer delete(int start, int end) {
        toStringCache = null;//缓存清空
        super.delete(start, end);//调用父类delete
        return this;
    }
//父类delete
 public AbstractStringBuilder delete(int start, int end) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            end = count;
        if (start > end)
            throw new StringIndexOutOfBoundsException();
        int len = end - start;
        if (len > 0) {
            System.arraycopy(value, start+len, value, start, count-end);
            count -= len;
        }
        return this;
    }

前面很多地方的底层源码都涉及到了System.arrayCopy()这个方法,这里就来使用一下。

 				char[] arr1={'a','b','c','d','e'};
        char[] arr2=new char[10];
/*
第一个参数是源数组,第二个参数是从源数组的哪个下标开始复制;第三个参数是目标数组,第四个参数是复制到目标数组的起始位置,第五个参数则是复制长度。
*/
        System.arraycopy(arr1, 0, arr2, 1, 5);
        for (char c : arr2) {
            System.out.println(c);
        }

将字符串插入此字符序列中。

StringBuffer sb=new StringBuffer("abc");
        sb.insert(1, "de");
        System.out.println(sb);//adebc

//源码分析
@Override
    public synchronized StringBuffer insert(int offset, String str) {
        toStringCache = null;//缓存区清空
        super.insert(offset, str);
        return this;
    }

使用给定 String 中的字符替换此序列的子字符串中的字符。

StringBuffer sb=new StringBuffer("abc");
        sb.replace(1, 2, "de");
        System.out.println(sb);//adec

将此字符序列用其反转形式取代。

 StringBuffer sb=new StringBuffer("abc");
        sb.reverse();
        System.out.println(sb);//cba

toStringCache,缓冲区,修改StringBuffer会被清空,只有在打印输出的时候有用

 @Override
    public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

StringBuilder和StringBuffer差不多,区别在于:StringBuilder没有缓冲区,并且StringBuilder是线程不安全的。

为什么String是不可变的,而StringBuilder和StringBuffer是可变的?

//String类的concat方法
public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);//创建了新的String字符串,而不是返回this
    }

//StringBuilder和StringBuffer共同父类AbstractStringBuilder的append方法
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;
    }

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);
        }
  //只是将追加的字符串的value字符数组拷贝到StringBuilder或者StringBuffer的value字符数组中,并没有创建新的StringBuilder或者StringBuffer
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值