1.3JDK源码阅读之String

Posted 康子的自留地

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1.3JDK源码阅读之String相关的知识,希望对你有一定的参考价值。

String源码分析

简介

Java语言中,String 代表的是不可变的字符序列,为不可变对象,一旦被创建,就不能修改它的值,对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去,正是因为其不可变,所以它是线程安全地,可以多个线程共享。

类声明

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

String 类被声明为 final,说明它不能再被继承。同时它实现了三个接口,分别为 Serializable、Comparable 和 CharSequence。 其中 Serializable 接口表明其可以序列化; Comparable这个接口只有一个方法,那就是CompareTo。所有想要具有比较功能的类,都建议实现这个接口; CharSequence 是 char 值的一个可读字符序列,String, StringBuilder和StringBuffer本质上都是通过字符数组实现的。

变量

 
   
   
 
  1. /** 用于存储字符串 */

  2. private
    final char value[];

  3. /** 缓存字符串对象的哈希值,默认值为0 */

  4. private
    int hash;


  5. /**用于排序的比较器 CaseInsensitiveComparator为内部类*/

  6. public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();

  7. /**

  8. * seed value used for each alternative hash calculated.

  9. * 用于计算每个备选哈希的种子值。 没搞明白 先不管

  10. */

  11. private
    static final int HASHING_SEED;

内部类

CaseInsensitiveComparator 提供排序的比较器,实现了Comparator接口和compare方法,另外一个readResolve方法用于替换反序列化时的对象。

 
   
   
 
  1. private static class CaseInsensitiveComparator

  2. implements Comparator<String>, java.io.Serializable {

  3. // use serialVersionUID from JDK 1.2.2 for interoperability

  4. private static final long serialVersionUID = 8575799808933029326L;


  5. public int compare(String s1, String s2) {

  6. int n1 = s1.length();

  7. int n2 = s2.length();

  8. //取二者长度最小值

  9. int min = Math.min(n1, n2);

  10. //以最小值为最大循环次数开启循环比较

  11. for (int i = 0; i < min; i++) {

  12. char c1 = s1.charAt(i);

  13. char c2 = s2.charAt(i);

  14. //如果字符不等

  15. if (c1 != c2) {

  16. c1 = Character.toUpperCase(c1);

  17. c2 = Character.toUpperCase(c2);

  18. // 如果字符的大写不等

  19. if (c1 != c2) {

  20. c1 = Character.toLowerCase(c1);

  21. c2 = Character.toLowerCase(c2);

  22. // 如果字符的小写不等

  23. if (c1 != c2) {

  24. // No overflow because of numeric promotion

  25. return c1 - c2;

  26. }

  27. }

  28. }

  29. }

  30. return n1 - n2;

  31. }

  32. }

判断了大写的情况还判断小写的原因是:由于自然语言的变幻莫测,有两种不同的Unicode字符具有相同的大写或小写的情况

构造器

 
   
   
 
  1. /**没有参数的构造方法直接将空字符串的 value 进行赋值*/

  2. public String() {

  3. this.value = new char[0];

  4. }

  5. /**传入 String 对象的构造方法则将该对象对应的 value 和 hash 进行赋值。*/

  6. public String(String original) {

  7. this.value = original.value;

  8. this.hash = original.hash;

  9. }

  10. /**构造方法传入 char 数组时,将数组数据复制为字符串*/

  11. public String(char value[]) {

  12. this.value = Arrays.copyOf(value, value.length);

  13. }

方法

1. length() 得到字符的长度

 
   
   
 
  1. public int length() {

  2. return value.length;

  3. }

2.isEmpty() 通过判断数组长度判断字符串是否为空

 
   
   
 
  1. public boolean isEmpty() {

  2. return value.length == 0;

  3. }

3. charAt(int index) 返回指定索引的char值 索引范围限制在 大于等于0小于字符串长度之间

 
   
   
 
  1. public char charAt(int index) {

  2. if ((index < 0) || (index >= value.length)) {

  3. throw new StringIndexOutOfBoundsException(index);

  4. }

  5. return value[index];

  6. }

4. codePointAt(int index) 获取字符串对应索引的 Unicode 代码点

 
   
   
 
  1. public int codePointAt(int index) {

  2. if ((index < 0) || (index >= value.length)) {

  3. throw new StringIndexOutOfBoundsException(index);

  4. }

  5. return Character.codePointAtImpl(value, index, value.length);

  6. }

5. codePointBefore(int index) 获取字符串对应索引的前一个 Unicode 代码点 实现和codePointAt一样 只是索引减一了

 
   
   
 
  1. public int codePointBefore(int index) {

  2. int i = index - 1;

  3. if ((i < 0) || (i >= value.length)) {

  4. throw new StringIndexOutOfBoundsException(index);

  5. }

  6. return Character.codePointBeforeImpl(value, index, 0);

  7. }

6. codePointCount(int beginIndex, int endIndex) 用于得到指定索引范围内代码点的个数

 
   
   
 
  1. public int codePointCount(int beginIndex, int endIndex) {

  2. if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {

  3. throw new IndexOutOfBoundsException();

  4. }

  5. return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);

  6. }

7. offsetByCodePoints(int index, int codePointOffset) 返回此 String 中从给定的 index 处偏移 codePointOffset 个代码点的索引

 
   
   
 
  1. public int offsetByCodePoints(int index, int codePointOffset) {

  2. if (index < 0 || index > value.length) {

  3. throw new IndexOutOfBoundsException();

  4. }

  5. return Character.offsetByCodePointsImpl(value, 0, value.length,

  6. index, codePointOffset);

  7. }

8. getChars(char dst[], int dstBegin) 用于获取字符串对象指定范围内的字符到目标 char 数组中

 
   
   
 
  1. void getChars(char dst[], int dstBegin) {

  2. System.arraycopy(value, 0, dst, dstBegin, value.length);

  3. }

9. getBytes 获取字节码数组

10. equals用于比较两字符串对象是否相等

如果引用相同则返回 true。否则判断比较对象是否为 String 类的实例,是的话转成 String 类型,接着比较编码是否相同

11. contentEquals 比较字符串之间内容是否相等

如果为 AbstractStringBuilder 实例化出来,是的话表示它为 StringBuilder 或 StringBuffer 对象。 如果为 StringBuffer 对象,说明它是线程安全的,需要做同步处理,调用nonSyncContentEquals方法。 如果为 StringBuilder 对象,它是非线程安全的,直接调用nonSyncContentEquals方法。 如果为 String 对象,则调用equals方法比较。 接下去的逻辑属于 CharSequence 对象时的逻辑。如果长度不相等直接返回 false。

12. equalsIgnoreCase 对比字符串是否相等,而且是忽略大小写。

13. compareTo/compareToIgnoreCase(忽略大小写)

按字典顺序比较两个字符串。该比较基于字符串中各个字符的 Unicode 值。按字典顺序将此 String 对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。如果这两个字符串相等,则结果为 0;compareTo 只在方法 equals(Object) 返回 true 时才返回 0。

14. regionMatches 检测指定区域字符串是否相等

15. startsWith 检测字符串是否以某个前缀开始,并且可以指定偏移。

16. endsWith 检测是否以某个字符串结尾,间接调用startsWith方法即可实现。

17. hashCode 返回字符串对象的哈希值,如果已经有缓存了则直接返回,否则就计算哈希值。

18. indexOf 用于查找字符串中第一个出现某字符或字符串的位置

有多种方法参数比如:可传入 int 类型,也可传入 String 类型,另外还能传入开始位置

  1. lastIndexOf 返回指定字符在此字符串中最后一次出现处的索引 和indexOf类似的实现

20. substring 用于获取字符串的指定子字符串。

有两个方法,一个是只传入开始索引,第二个是出传入开始索引和结束索引。

21. subSequence 等同于substring 方法

只是返回的类型不一样 这个返回的是CharSequence类型

22. concat 将指定的字符串参数连接到字符串上

23. replace 用于替换字符串中指定的字符

24. split 用于切分字符串

实现中首先会判断能不能不用正则引擎,如果可以则直接切分,否则采用正则引擎切分。

25. join (A (String), B (String[]));

在指定 String 数组B的每个元素之间串联指定的分隔符 A,从而产生单个串联的字符串 string [] tmpStr={abc,def,ghi}; string join = string.join(“|“, tmpStr); 此时 join =”abc|def|ghi”;

26. toLowerCase 将字符串成转成小写、toUpperCase 将字符串成转成大写

27. trim 用于删除字符串的头尾空白符

28. toString 返回字符串 直接返回this

29. toCharArray 将字符串转成 char 数组

30. format 格式化字符串

31. valueOf 将传入的对象转成 String 对象,可传入多种类型参数

Objet 时,为空则返回”null”字符串,否则obj.toString()。 char 数组时,直接new 一个 String 对象。 boolean 时,返回”true” 或 “false”字符串。 char 时,优先尝试转成 Latin1 编码的 String 读,否则用 UTF16。 int 时,Integer.toString(i)。 long 时,Long.toString(l)。 float 时,Float.toString(f)。 double 时,Double.toString(d)。

32. public native String intern();

标记了 native 的本地方法,字符串对象调用intern方法会先检查池中是否已经存在该字符串的标准对象,如果存在则直接返回标准对象,如果不存在则会往池中创建标准对象并且返回该对象。 可以在有大量重复字符串的场景下使用 以用来达到优化内存的效果 ps:100w的字符串对象里面有70w重复的对象 使用这个 可以把字符串对象数量缩小到30w

往期精选




如果你喜欢这篇文章,点好看,点转发。

Life is fantastic!明天见(。・ω・。)ノ♡

以上是关于1.3JDK源码阅读之String的主要内容,如果未能解决你的问题,请参考以下文章

jdk 源码阅读有感String

阅读JDK源码后,我有了优化它的冲动!

JDK10源码阅读--String

1.1JDK源码阅读之阅读顺序

JDK1.8源码分析03之idea搭建源码阅读环境

JDK1.8源码分析02之阅读源码顺序