• 【Java】- 源码解析——String类


    摘要:

      解析一个类我们从以下方面来入手

        1、类定义(继承,实现接口等)

        2、全局变量(属性)

        3、内部类

        4、方法

    一、String类的定义:

      1、实现接口:

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

      java.io.Serializable

        序列化接口,没有任何方法,仅用于在反序列化时进行版本的比对

      Comparable

        这个接口只有一个compareTo(T 0)接口,用于对两个实例化对象比较大小。

      CharSequence

        这个接口是一个只读的字符序列。包括length(), charAt(int index), subSequence(int start, int end)这几个API接口,值得一提的是,StringBuffer和StringBuild也是实现了改接口。

    二、属性

      1、String 不可变特性

    1     /*
    2          private final char value[],体现了String类型的不可变特性
    3          1、value[] 数组在对象创建时就初始化了长度,且长度不可变
    4          2、final修饰,导致数组的引用地址不可以被改变
    5          3、private修饰,表示不可被外部类进行访问,也就是说在外部类不可调用,所以数组的内容不可被改变
    6          长度不可变,内容不可变,地址不可变,从而导致String的对象内容不可变,可以推理出,
    7          我们所看到的一切String字符串的增删改操作都是重新创建了对象,使变量来指向新的对象地址
    8 */
    9         private final char value[];

      2、hash

    1 /*
    2             而hash是String实例化的hashcode的一个缓存。因为String经常被用于比较,比如在HashMap中。
    3             如果每次进行比较都重新计算hashcode的值的话,那无疑是比较麻烦的,而保存一个hashcode的缓存无疑能优化这样的操作。
    4          */
    5         private int hash; // Default to 0

    三、内部类

     1  // 单例模式,声明静态常量,用于调用内部类CaseInsensitiveComparator中compare()方法
     2         public static final Comparator<String> CASE_INSENSITIVE_ORDER
     3                 = new CaseInsensitiveComparator();
     4 
     5         // 实现 Comparator java.io.Serializable 两个接口直接创建内部类
     6         private static class CaseInsensitiveComparator
     7                 implements Comparator<String>, java.io.Serializable {
     8             // use serialVersionUID from JDK 1.2.2 for interoperability
     9             private static final long serialVersionUID = 8575799808933029326L;
    10 
    11             public int compare(String s1, String s2) {
    12                 int n1 = s1.length();
    13                 int n2 = s2.length();
    14                 int min = Math.min(n1, n2); // 获取字符串s1和s2较短的一个赋值给min
    15                 for (int i = 0; i < min; i++) {
    16                     char c1 = s1.charAt(i);
    17                     char c2 = s2.charAt(i);
    18                     if (c1 != c2) {
    19                         // 将遍历的字符串变转换为大写在进行比较
    20                         c1 = Character.toUpperCase(c1);
    21                         c2 = Character.toUpperCase(c2);
    22                         if (c1 != c2) {
    23                             // 将遍历的字符串在转换为小写在进行比较
    24                             c1 = Character.toLowerCase(c1);
    25                             c2 = Character.toLowerCase(c2);
    26                             if (c1 != c2) {
    27                                 // No overflow because of numeric promotion
    28                                 return c1 - c2; // 若是不相等,返回小写字符对应的Ascii码之差
    29                             }
    30                         }
    31                     }
    32                 }
    33                 return n1 - n2; // 若是存在字符串为null 则返回两个字符串长度之差
    34             }
    35 
    36             /** Replaces the de-serialized object. */
    37             private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    38         }

    四、方法

      1、构造函数

      1 // 无参构造方法 相当于 String str = ""
      2         public String() {
      3             this.value = "".value;
      4         }
      5 
      6         /*
      7            初始化新创建的String对象,使其表示与参数相同的字符序列; 换句话说,新创建的字符串是参数字符串的副本。
      8            String str1 = "abc";
      9            String str2 = new String(str1);
     10          */
     11          public String(String original) {
     12             this.value = original.value;
     13             this.hash = original.hash;
     14         }
     15 
     16         /*
     17             定义一个char数组,来构建一个String对象
     18             char[] value = new char[]{'a','b'}
     19             String str1 = new String(value)
     20          */
     21         public String(char value[]) {
     22             this.value = Arrays.copyOf(value, value.length);
     23         }
     24 
     25         /*
     26             给定一个char[],根据offset偏移量,count偏移长度来截取后构建一个新的String对象
     27             char[] value = new char[]{'h','e','l','l','o'}
     28             String str2 = new String(value, 1, 3)
     29             输出str2为:ell
     30          */
     31         public String(char value[], int offset, int count) {
     32             // 偏移量小于0时 抛出字符串截取下标越界异常StringIndexOutOfBoundsException
     33             if (offset < 0) {
     34                 throw new StringIndexOutOfBoundsException(offset);
     35             }
     36             if (count <= 0) {
     37                 // 截取长度<0时 抛出字符串截取下标越界异常StringIndexOutOfBoundsException
     38                 if (count < 0) {
     39                     throw new StringIndexOutOfBoundsException(count);
     40                 }
     41                 //偏移量<=字符串长度且截取值count==0,直接将value赋值为"",并返回空
     42                 if (offset <= value.length) {
     43                     this.value = "".value;
     44                     return;
     45                 }
     46             }
     47             // Note: offset or count might be near -1>>>1.
     48             // 偏移量+截取长度大于字符串总长度则抛出字符串截取下标越界异常StringIndexOutOfBoundsException异常
     49             if (offset > value.length - count) {
     50                 throw new StringIndexOutOfBoundsException(offset + count);
     51             }
     52             // 重新按照偏移量和截取长度来构建value数组值
     53             this.value = Arrays.copyOfRange(value, offset, offset+count);
     54         }
     55 
     56         /*
     57             给定一个字节码数组,根据offset偏移量,count偏移长度来截取后构建一个新的String对象
     58          */
     59         public String(int[] codePoints, int offset, int count) {
     60             if (offset < 0) {
     61                 throw new StringIndexOutOfBoundsException(offset);
     62             }
     63             if (count <= 0) {
     64                 if (count < 0) {
     65                     throw new StringIndexOutOfBoundsException(count);
     66                 }
     67                 if (offset <= codePoints.length) {
     68                     this.value = "".value;
     69                     return;
     70                 }
     71             }
     72             // Note: offset or count might be near -1>>>1.
     73             if (offset > codePoints.length - count) {
     74                 throw new StringIndexOutOfBoundsException(offset + count);
     75             }
     76 
     77             final int end = offset + count;
     78 
     79             // Pass 1: Compute precise size of char[]
     80             int n = count;
     81             for (int i = offset; i < end; i++) {
     82                 int c = codePoints[i];
     83                 if (Character.isBmpCodePoint(c))
     84                     continue;
     85                 else if (Character.isValidCodePoint(c))
     86                     n++;
     87                 else throw new IllegalArgumentException(Integer.toString(c));
     88             }
     89 
     90             // Pass 2: Allocate and fill in char[]
     91             final char[] v = new char[n];
     92 
     93             for (int i = offset, j = 0; i < end; i++, j++) {
     94                 int c = codePoints[i];
     95                 if (Character.isBmpCodePoint(c))
     96                     v[j] = (char)c;
     97                 else
     98                     Character.toSurrogates(c, v, j++);
     99             }
    100 
    101             this.value = v;
    102         }
    103 
    104         /*
    105             分配一个新的字符串,其中包含当前包含在字符串缓冲区参数中的字符序列。
    106             StringBuffer来构建String对象,比较常用
    107          */
    108         public String(StringBuffer buffer) {
    109             synchronized(buffer) {
    110                 this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
    111             }
    112         }
    113 
    114         /*
    115             分配一个新的字符串,其中包含当前包含在字符串构建器参数中的字符序列。
    116             StringBuilder来构建String对象,比较常用
    117          */
    118         public String(StringBuilder builder) {
    119             this.value = Arrays.copyOf(builder.getValue(), builder.length());
    120         }

      2、方法

     1      // 判断字符串长度
     2         public int length() {
     3             return value.length;
     4         }
     5 
     6         // 判断字符串是否为空
     7         public boolean isEmpty() {
     8             return value.length == 0;
     9         }
    10 
    11         // 获取指定index位置的字符串字符
    12         public char charAt(int index) {
    13             if ((index < 0) || (index >= value.length)) {
    14                 throw new StringIndexOutOfBoundsException(index);
    15             }
    16             return value[index];
    17         }
    18         // 备注:因字符串在内存其实是通过char[]来进行存储,上面三个方法实际上就是操作数组来进行返回值

        以下常用方法不进行源代码展示,其实也是对数据进行操作,详情可以去看源码

        1)、int  codePointAt(int index)  返回指定索引处的字符(Unicode代码点)。 

        2)、int  codePointBefore(int index)  返回指定索引之前的字符(Unicode代码点)。

        3)、int  codePointCount(int beginIndex, int endIndex)  返回此 String指定文本范围内的Unicode代码点数。

        4)、boolean  equals()方法重写源码解析

     1      // equals继承自Object类
     2         // 在String类中将该方法进行重写
     3         public boolean equals(Object anObject) {
     4             // 判断传入的对象和当前对象是否地址相等,若是引用地址相等则返回true
     5             if (this == anObject) {
     6                 return true;
     7             }
     8             // 判断传入的对象是否为String类实例对象,若不是String类实例对象则返回false
     9             if (anObject instanceof String) {
    10                 String anotherString = (String)anObject; // 将anObject进行造型为String类型
    11                 int n = value.length;
    12                 // 判断传入的对象内容即字符串长度是否和当前类中的字符串长度相等
    13                 if (n == anotherString.value.length) {
    14                     char v1[] = value;
    15                     char v2[] = anotherString.value;
    16                     int i = 0;
    17                     while (n-- != 0) {
    18                         // 循环遍历字符串进行值比较
    19                         if (v1[i] != v2[i])
    20                             return false;
    21                         i++;
    22                     }
    23                     return true;
    24                 }
    25             }
    26             return false;
    27         }

        5)、int  hashCode()方法重写源码解析

     1      public int hashCode() {
     2             // 将默认值hash=0赋值给h
     3             int h = hash;
     4             if (h == 0 && value.length > 0) {
     5                 char val[] = value;
     6                 for (int i = 0; i < value.length; i++) {
     7                     /* 循环遍历字符串字符进行计算以字符串"ABC"为例
     8                         当为A时   0*31 + 65
     9                         当为B时   65*31 + 66
    10                         当为C时   (65*31 + 66) * 31 + 67
    11                     */
    12                     h = 31 * h + val[i];
    13                 }
    14                 // 将计算后的hashCode值放入 私有属性 hash中
    15                 hash = h;
    16             }
    17             return h;
    18         }

        6)、boolean  compareTo()方法源码解析

     1 // 1、分别获取当前对象字符串长度和传入字符串的长度
     2         // 2、按照字符串长度短的进行循环遍历
     3         // 3、若是遍历完后的字符对应的字节码值全部相等,则返回两个字符串的长度差值,若是长度也相等则返回0
     4         // 4、若是遍历存在字符串对应的字节码不相等,则直接返回字符串对应的不相同的字符的字节码之差
     5         public int compareTo(String anotherString) {
     6             int len1 = value.length;
     7             int len2 = anotherString.value.length;
     8             int lim = Math.min(len1, len2);
     9             char v1[] = value;
    10             char v2[] = anotherString.value;
    11 
    12             int k = 0;
    13             while (k < lim) {
    14                 char c1 = v1[k];
    15                 char c2 = v2[k];
    16                 if (c1 != c2) {
    17                     return c1 - c2;
    18                 }
    19                 k++;
    20             }
    21             return len1 - len2;
    22         }

        7)、Stri ng  concat(String str)  将指定的字符串连接到该字符串的末尾。

        8)、boolean  contains(CharSequence s)  判断字符串中是否包含指定的字符

        9)、int  indexOf(int ch)  返回指定字符第一次出现的字符串内的索引。

           int  indexOf(int ch, int fromIndex)  返回指定字符第一次出现的字符串内的索引,以指定的索引开始搜索。

           int  indexOf(String str)  返回指定子字符串第一次出现的字符串内的索引。

           int  indexOf(String str, int fromIndex)  返回指定子串的第一次出现的字符串中的索引,从指定的索引开始。

        10)、int  lastIndexOf(int ch)  返回指定字符的最后一次出现的字符串中的索引。

           int  lastIndexOf(int ch, int fromIndex)  返回指定字符的最后一次出现的字符串中的索引,从指定的索引开始向后搜索。

           int  lastIndexOf(String str)  返回指定子字符串最后一次出现的字符串中的索引。

           int  lastIndexOf(String str, int fromIndex)  返回指定子字符串的最后一次出现的字符串中的索引,从指定索引开始向后搜索。

        11)、String  replace(char oldChar, char newChar)  返回从替换所有出现的导致一个字符串 oldChar在此字符串 newChar 。
           String  replace(CharSequence target, CharSequence replacement)  将与字面目标序列匹配的字符串的每个子字符串替换为指定的字面替换序列。

           String  replaceAll(String regex, String replacement)  用给定的替换替换与给定的 regular expression匹配的此字符串的每个子字符串。

           String  replaceFirst(String regex, String replacement)  用给定的替换替换与给定的 regular expression匹配的此字符串的第一个子字符串。

        12)、String[]  split(String regex)  将此字符串分割为给定的 regular expression的匹配。

        13)、boolean  startsWith(String prefix)  测试此字符串是否以指定的前缀开头。

        14)、String  substring(int beginIndex)  从beginIndex开始截取字符串至结尾

           Striing  substring(int beginIndex, int endIndex)  从(beginIndex开始截取字符串至endIndex],

        15)、char[]  toCharArray()  将此字符串转换为新的字符数组。

        16)、String  toString()  此对象(已经是字符串!)本身已被返回。

    1     // 重写Object中的方法
    2         public String toString() {
    3             return this;
    4         }

        17)、String  trim()  返回一个字符串,其值为此字符串,并删除任何前导和尾随空格。

        

  • 相关阅读:
    计算机的组成部分
    从LINQ开始之LINQ to Objects(下)
    从LINQ开始之LINQ to Objects(上)
    vue.js devtools-------调试vue.js的开发者插件
    Sublime快捷键(一)
    配置node,sass,淘宝镜像环境
    vue--------脚手架vue-cli搭建
    Sublime之插件的安装(一)
    计算机网络之万维网WWW
    官网下载java相关资源
  • 原文地址:https://www.cnblogs.com/tar8087/p/14438997.html
Copyright © 2020-2023  润新知