JDK1.8源码——java.lang.String 类

 

 


 

String 类也是java.lang 包下的一个类,算是日常编码中最常用的一个类了,那么本篇博客就来详细的介绍 String 类。

1、String 类的定义

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

  和上一篇博客所讲的 Integer 类一样,这也是一个用 final 声明的常量类,不能被任何类所继承,而且一旦一个String对象被创建, 包含在这个对象中的字符序列是不可改变的, 包括该类后续的所有方法都是不能修改该对象的,直至该对象被销毁,这是我们需要特别注意的(该类的一些方法看似改变了字符串,其实内部都是创建一个新的字符串,下面讲解方法时会介绍)。接着实现了 Serializable接口,这是一个序列化标志接口,还实现了 Comparable 接口,用于比较两个字符串的大小(按顺序比较单个字符的ASCII码),后面会有具体方法实现;最后实现了 CharSequence 接口,表示是一个有序字符的集合,相应的方法后面也会介绍。

2、字段属性

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

/** Cache the hash code for the string */
private int hash; // Default to 0

/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;

  一个 String 字符串实际上是一个 char 数组。

3、构造方法

  String 类的构造方法很多。可以通过初始化一个字符串,或者字符数组,或者字节数组等等来创建一个 String 对象。

  

String str1 = "abc";//注意这种字面量声明的区别,文末会详细介绍
String str2 = new String("abc");
String str3 = new String(new char[]{'a','b','c'})

4、equals(Object anObject) 方法

instanceof 运算符 用于:判断 该运算符前面引用类型变量指向的对象是否是后面类,或者其子类、接口实现类创建的对象。如果是则返回true,否则返回false,

其使用格式如下:     引用类型变量 instanceof (类、抽象类或接口)
 1 /**
 2      * Compares this string to the specified object.  The result is {@code
 3      * true} if and only if the argument is not {@code null} and is a {@code
 4      * String} object that represents the same sequence of characters as this
 5      * object.
 6      *
 7      * @param  anObject
 8      *         The object to compare this {@code String} against
 9      *
10      * @return  {@code true} if the given object represents a {@code String}
11      *          equivalent to this string, {@code false} otherwise
12      *
13      * @see  #compareTo(String)
14      * @see  #equalsIgnoreCase(String)
15      */
16     public boolean equals(Object anObject) {
17         if (this == anObject) {
18             return true;
19         }
20         if (anObject instanceof String) {
21             String anotherString = (String)anObject;
22             int n = value.length;
23             if (n == anotherString.value.length) {
24                 char v1[] = value;
25                 char v2[] = anotherString.value;
26                 int i = 0;
27                 //比较每一个字符的值
28                 while (n-- != 0) {
29                     if (v1[i] != v2[i])
30                         return false;
31                     i++;
32                 }
33                 return true;
34             }
35         }
36         return false;
37     }

String 类重写了 equals 方法,比较的是组成字符串的每一个字符是否相同,如果都相同则返回true,否则返回false。

5、hashCode() 方法

 1     /**
 2      * Compares this string to the specified object.  The result is {@code
 3      * true} if and only if the argument is not {@code null} and is a {@code
 4      * String} object that represents the same sequence of characters as this
 5      * object.
 6      *
 7      * @param  anObject
 8      *         The object to compare this {@code String} against
 9      *
10      * @return  {@code true} if the given object represents a {@code String}
11      *          equivalent to this string, {@code false} otherwise
12      *
13      * @see  #compareTo(String)
14      * @see  #equalsIgnoreCase(String)
15      */
16     public boolean equals(Object anObject) {
17         if (this == anObject) {
18             return true;
19         }
20         if (anObject instanceof String) {
21             String anotherString = (String)anObject;
22             int n = value.length;
23             if (n == anotherString.value.length) {
24                 char v1[] = value;
25                 char v2[] = anotherString.value;
26                 int i = 0;
27                 while (n-- != 0) {
28                     if (v1[i] != v2[i])
29                         return false;
30                     i++;
31                 }
32                 return true;
33             }
34         }
35         return false;
36     }

 String 类的 hashCode 算法很简单,主要就是中间的 for 循环,计算公式如下:

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

  s 数组即源码中的 val 数组,也就是构成字符串的字符数组。这里有个数字 31 ,为什么选择31作为乘积因子,而且没有用一个常量来声明?主要原因有两个:

  ①、31是一个不大不小的质数,是作为 hashCode 乘子的优选质数之一。

  ②、31可以被 JVM 优化,31 * i = (i << 5) - i。因为移位运算比乘法运行更快更省性能。

具体解释可以参考这篇文章https://www.cnblogs.com/nullllun/p/8350178.html

6.split(String regex) 和 split(String regex, int limit) 方法

 split(String regex) 将该字符串拆分为给定正则表达式的匹配。split(String regex , int limit) 也是一样,不过对于 limit 的取值有三种情况:

  ①、limit > 0 ,则pattern(模式)应用n - 1 次

1 String str = "a,b,c";
2 String[] c1 = str.split(",", 2);
3 System.out.println(c1.length);//2
4 System.out.println(Arrays.toString(c1));//{"a","b,c"}

  ②、limit = 0 ,则pattern(模式)应用无限次并且省略末尾的空字串

1 String str2 = "a,b,c,,";
2 String[] c2 = str2.split(",", 0);
3 System.out.println(c2.length);//3
4 System.out.println(Arrays.toString(c2));//{"a","b","c"}

  ③、limit < 0 ,则pattern(模式)应用无限次

1 String str2 = "a,b,c,,";
2 String[] c2 = str2.split(",", -1);
3 System.out.println(c2.length);//5
4 System.out.println(Arrays.toString(c2));//{"a","b","c","",""}

  下面我们看看底层的源码实现。对于 split(String regex) 没什么好说的,内部调用  split(regex, 0) 方法:

1  public String[] split(String regex) {
2         return split(regex, 0);
3  }

  重点看 split(String regex, int limit) 的方法实现:

 1 public String[] split(String regex, int limit) {
 2     /* 1、单个字符,且不是".$|()[{^?*+\\"其中一个
 3      * 2、两个字符,第一个是"\",第二个大小写字母或者数字
 4      */
 5     char ch = 0;
 6     if (((regex.value.length == 1 &&
 7          ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
 8          (regex.length() == 2 &&
 9           regex.charAt(0) == '\\' &&
10           (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
11           ((ch-'a')|('z'-ch)) < 0 &&
12           ((ch-'A')|('Z'-ch)) < 0)) &&
13         (ch < Character.MIN_HIGH_SURROGATE ||
14          ch > Character.MAX_LOW_SURROGATE))
15     {
16         int off = 0;
17         int next = 0;
18         boolean limited = limit > 0;//大于0,limited==true,反之limited==false
19         ArrayList<String> list = new ArrayList<>();
20         while ((next = indexOf(ch, off)) != -1) {
21             //当参数limit<=0 或者 集合list的长度小于 limit-1
22             if (!limited || list.size() < limit - 1) {
23                 list.add(substring(off, next));
24                 off = next + 1;
25             } else {//判断最后一个list.size() == limit - 1
26                 list.add(substring(off, value.length));
27                 off = value.length;
28                 break;
29             }
30         }
31         //如果没有一个能匹配的,返回一个新的字符串,内容和原来的一样
32         if (off == 0)
33             return new String[]{this};
34 
35         // 当 limit<=0 时,limited==false,或者集合的长度 小于 limit是,截取添加剩下的字符串
36         if (!limited || list.size() < limit)
37             list.add(substring(off, value.length));
38 
39         // 当 limit == 0 时,如果末尾添加的元素为空(长度为0),则集合长度不断减1,直到末尾不为空
40         int resultSize = list.size();
41         if (limit == 0) {
42             while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
43                 resultSize--;
44             }
45         }
46         String[] result = new String[resultSize];
47         return list.subList(0, resultSize).toArray(result);
48     }
49     return Pattern.compile(regex).split(this, limit);
50 }

 

posted @ 2020-05-03 18:59  小辣椒樱桃  阅读(370)  评论(0编辑  收藏  举报