JDK1.8源码解读之 String类

357 阅读4分钟

概述

String 相对于StringBuffer 和 StringBuilder。 String 的特点是不可变。一旦创建就不可变。

继承关系

实现了3个接口 implements java.io.Serializable,Comparable, CharSequence

重要成员属性

private final char value[];

String的底层是采用char[]来存储数据的。若给String类型的对象重新赋值,其实是指引用了一个 重新创建的char[]。String类型的不可变,其实是指引用char[]本身没有改变,只是String的引用发生了变化。

构造器

生成一个新的String对象。

public String() {
    this.value = "".value;
}

还有其他若干重载的构造器:

public String(java.lang.String)
public String(char[])
public String(char[], int, int)
public String(int[], int, int)
public String(byte[], int, int, int)
public String(byte[], int)
public String(byte[], int, int, java.lang.String)
public String(byte[], int, int, Charset)
public String(byte[], java.lang.String)
public String(byte[], Charset)
public String(byte[], int, int)
public String(byte[])
public String(StringBuffer)
public String(StringBuilder)

关键方法

+ length()

返回字符串长度

public int length() {
    return value.length;
}
+ isEmpty()

判断是否为空,当且仅当String对象的长度为0时,返回true

public boolean isEmpty() {
    return value.length == 0;
}
+ charAt(int index)

返回指定序号处的字符

public char charAt(int index) {
    if ((index < 0) || (index >= value.length)) {
        throw new StringIndexOutOfBoundsException(index);
    }
    return value[index];
}
+ getBytes()

使用平台默认的字符集,将String对象转化为byte序列存储到一个新的数组中。

public byte[] getBytes() {
    return StringCoding.encode(value, 0, value.length);
}
+ equals()

当切仅当另一个对象也是String,并且两个String包含的字符序列相同时,返回true。

public boolean equals(Object anObject) { ... }

此外还有public boolean equalsIgnoreCase()方法,忽略大小写进行比较。

+ contentEquals()

和一个对象比较,如果字符序列相同,那么返回true。 如果

public boolean contentEquals(StringBuffer sb) {
    return contentEquals((CharSequence)sb);
}
public boolean contentEquals(CharSequence cs) {
    ...
}
+ compareTo(String anotherString)

怎么比较呢。举个例子;

  1. String str1 = "abc"; String str2 = "abcd"; 从前到后开始比较,发现两个字符串公共部分完全一致,但是另一个字符串长度大一些,那么返回 str1.Length - str2.length
  2. String a = "123" String b = "134" 那么在index=1处,两个字符不一样,返回在字典中的位置差,即 "2" - "3",返回值 -1。
public int compareTo(String anotherString) { ... }
+ startsWith()

判断字符串是否以目标字符串开头。

public boolean startsWith(String prefix) { ... }
public boolean startsWith(String prefix, int toffset) { ... }
+ endsWith()

判断字符串是否以目标字符串结束。

public boolean endsWith(String suffix) { ... }
+ indexOf()

计算目标字符串第一次出现的位置的索引值。

public int indexOf(int ch, int fromIndex) { ... }
+ lastIndexOf()

判断目标字符串最后一次出现的位置的索引值。

public int lastIndexOf(int ch) { ... }
+ substring(int beginIndex)

根据开始索引,获取字符串的子串。

public String substring(int beginIndex) { ... }
+ concat()

把目标String添加到当前String末尾

public String concat(String str) { ... }
+ replace(char oldChar, char newChar)

把当前String中的oldChar替换为newChar。

public String replace(char oldChar, char newChar) { ... }
+ matches(String regex)

判断当前字符串是否符合目标正则

public boolean matches(String regex) {
    return Pattern.matches(regex, this);
}
+ contains(CharSequence s)

判断当前String是否包含目标字符串序列。

public boolean contains(CharSequence s) {
    return indexOf(s.toString()) > -1;
}
+ split(String regex)

以目标字符串作为分割符,将当前字符串分割为若干字符串,以String数组形式返回。

public String[] split(String regex) { ... }
public String[] split(String regex, int limit) { ... }
+ join(CharSequence delimiter, CharSequence... elements)

用指定的分隔符,将目标字符串数组拼接起来,返回String。

public static String join(CharSequence delimiter, CharSequence... elements) { ... }
public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) { ... }
+ toLowerCase(Locale locale)

转化为小写

public String toLowerCase(Locale locale) { ... }
+ toUpperCase(Locale locale)

转化为大写

public String toUpperCase(Locale locale) { ... }
public String toUpperCase() { ... }
trim()

去掉先后空格

public String trim() { ... }
valueOf()

返回代表目标对象的字符串实现的。各种

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

实现原理

String类的底层是采用字符数组实现的。各种操作其实都是基于字符数组的操作。

常见问题

问题一

以下代码的执行结果是?

String b = "abc";
String c = "abc";
System.out.println(b.equals(c));

>> true

因为字符串"abc"出现过,所以之后定义String的时候,其实是直接引用到第一次创建的"abc"。所以两个对象是相同的。

结语


需要区分String,StringBuffer,StringBuilder的特点和使用场景。 String常常用于存储是不可变的字符串序列。如果一个字符串需要频繁变更,那么最好是使用StringBuffer或者StringBuilder来存储。 StringBuffer和StringBuilder之间的区别在于: StringBuffer 是线程安全的。但是速度会相对慢。 StringBuilder 不是线程安全的,访问速度高。 所以在单线程中使用频繁变更的字符串,应该使用StringBuilder来存储。 在多线程中存储频繁变更的字符串,应该使用StringBuffer来存储。

希望和大家多多交流


我16年毕业以后,做的是前端,目前打算深入学习java开发。内容有任何问题,欢迎各位小伙伴们指正,也希望小伙伴们给我点赞和关注,给我留言,一起交流讨论,共同进步。