5_从源码分析java.lang.String

文章目录

从哪几个方面了解String

String的定义、字段属性、构造函数、API

一、 String的定义

1、 String的表面定义

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

2、 String是一个可继承的类吗?为什么?

String是一个final类,既不能被继承的类

3、 String类实现了java.io.Serializable接口的作用–>1

实现序列化

4、String类实现了Comparable接口的作用

可以用于比较大小(按顺序比较单个字符的ASCII码)

5、String类实现了 CharSequence 接口的作用

表示是一个有序字符的序列,因为String的本质是一个char类型数组

二、 字段属性

6、private final char value[]; 的作用

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

用来存字节的。这是String字符串的本质,是一个字符集合,而且是final的,是不可变的。

7、该成员变量被final修饰之后产生的效果

表示该字符串是不可变的。

8、private int hash;的作

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

缓存字符串的哈希值,默认是0

9、private static final long serialVersionUID = -6849794470754667710L;的作用

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

三、构造函数

10、String() 构造方法的作用

是空参构造方法

11、String(byte[] bytes) 的作用

通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String

12、用String(byte[] bytes)构造方法举个例子

    byte[] bytes = {97,98,99,100};
    String str = new String(bytes);
    System.out.println(str);

    the output:abcd

13、String(byte[] bytes, Charset charset) 的作用

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

14、Charset 类型的作用

指定解码类型,比如GBK,UTF-8等

15、String(byte[] bytes, int offset, int length) 的作用

通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于该子数组的长度。

参数:

bytes - 要解码为字符的 byte

offset - 要解码的第一个 byte 的索引

length - 要解码的 byte 数

抛出:

IndexOutOfBoundsException - 如果 offsetlength 参数索引字符超出 bytes 数组的范围

16、用String(byte[] bytes, int offset, int length)构造方法举例

  byte[] bytes = {97,98,99,100};
  String str = new String(bytes,2,2);
  System.out.println(str);

  the output:cd

17、String(byte[] bytes, int offset, int length, Charset charset)的作用

参数:

bytes - 要解码为字符的 byte

offset - 要解码的第一个 byte 的索引

length - 要解码的 byte 数

charset-用来解码 bytes的 charset

18、Charset类型所在包

java.nio.charset
类 Charset

java.lang.Object

java.nio.charset.Charset

所有已实现的接口:

Comparable<Charset>

19、String(byte[] bytes, int offset, int length, String charsetName)的作用

String

public String(byte[] bytes,
              int offset,
              int length,
              String charsetName)
       throws UnsupportedEncodingException

通过使用指定的字符集解码指定的 byte 子数组,构造一个新的 String。新 String 的长度是一个字符集函数,因此可能不等于子数组的长度。

当给定 byte 在给定字符集中无效的情况下,此构造方法的行为没有指定。如果需要对解码过程进行更多控制,则应该使用 CharsetDecoder 类。

参数:

bytes - 要解码为字符的 byte

offset - 要解码的第一个 byte 的索引

length - 要解码的 byte 数

charsetName - 受支持 charset 的名称

抛出:

UnsupportedEncodingException - 如果指定的字符集不受支持

IndexOutOfBoundsException - 如果 offsetlength 参数索引字符超出 bytes 数组的范围

从以下版本开始:

JDK1.1

20、String(byte[] bytes, String charsetName) 的作用

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

21、String(char[] value) 的作用

public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

四、API

22、长度

  public int length() {      
      //所以String的长度就是一个value的长度
      return value.length;
  }

23、是否为空函数

public boolean isEmpty() {  
    //当char数组的长度为0,则代表String为"",空字符串
    return value.length == 0;
}

24、charAt函数

/**
 * 返回String对象的char数组index位置的元素
 */
public char charAt(int index) {
    if ((index < 0) || (index >= value.length)) {   
        //index不允许小于0,不允许大于等于String的长度
        throw new StringIndexOutOfBoundsException(index);
    }
    return value[index]; //返回
}
  • 只有一个charAt()是针对字符而言的,就是寻找第index位置的字符是什么,在面试的算法中也很常会用到

25、codePointAt函数

 /**
 * 返回String对象的char数组index位置的元素的ASSIC码(int类型)
 */
public int codePointAt(int index) {
    if ((index < 0) || (index >= value.length)) {
        throw new StringIndexOutOfBoundsException(index);
    }
    return Character.codePointAtImpl(value, index, value.length);
}

26、codePointBefore函数

/**
* 返回index位置元素的前一个元素的ASSIC码(int型)
*/
public int codePointBefore(int index) {
    int i = index - 1;//获得index前一个元素的索引位置
    if ((i < 0) || (i >= value.length)) {//所以,index不能等于0,因为i = 0 - 1 = -1
        throw new StringIndexOutOfBoundsException(index);
    }
    return Character.codePointBeforeImpl(value, index, 0);
}

27、codePointCount函数

/**
* 方法返回的是代码点个数,是实际上的字符个数,功能类似于length()
* 对于正常的String来说,length方法和codePointCount没有区别,都是返回字符个数。
* 但当String是Unicode类型时则有区别了。
* 例如:String str = “/uD835/uDD6B” (即使 'Z' ), length() = 2 ,codePointCount() = 1 
*/
public int codePointCount(int beginIndex, int endIndex) {
    if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {
        throw new IndexOutOfBoundsException();
    }
    return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
}

28、offsetByCodePoints

/**
* 也是相对Unicode字符集而言的,从index索引位置算起,偏移codePointOffset个位置,返回偏移后的位置是多少
* 例如,index = 2 ,codePointOffset = 3 ,maybe返回 5 
*/
public int offsetByCodePoints(int index, int codePointOffset) {
    if (index < 0 || index > value.length) {
        throw new IndexOutOfBoundsException();
    }
    return Character.offsetByCodePointsImpl(value, 0, value.length,
            index, codePointOffset);
}

29、getChar函数

 /**
 * 这是一个不对外的方法,是给String内部调用的,因为它是没有访问修饰符的,只允许同一包下的类访问
 * 参数:dst[]是目标数组,dstBegin是目标数组的偏移量,既要复制过去的起始位置(从目标数组的什么位置覆盖)
 * 作用就是将String的字符数组value整个复制到dst字符数组中,在dst数组的dstBegin位置开始拷贝
 * 
 */
void getChars(char dst[], int dstBegin) {
    System.arraycopy(value, 0, dst, dstBegin, value.length);
}

30、equals方法的实现

/**

 - String的equals方法,重写了Object的equals方法(区分大小写)
 - 比较的是两个字符串的值是否相等
 - 参数是一个Object对象,而不是一个String对象。这是因为重写的是Object的equals方法,所以是Object
 - 如果是String自己独有的方法,则可以传入String对象,不用多此一举
 - 
 - 实例:str1.equals(str2)
 */
public boolean equals(Object anObject) {
    if (this == anObject) {   //首先判断形参str2是否跟当前对象str1是同一个对象,既比较地址是否相等
        return true;          //如果地址相等,那么自然值也相等,毕竟是同一个字符串对象
    }
    if (anObject instanceof String) {  //判断str2对象是否是一个String类型,过滤掉非String类型的比较
        String anotherString = (String)anObject; //如果是String类型,转换为String类型
        int n = value.length;                    //获得当前对象str1的长度
        if (n == anotherString.value.length) {   //比较str1的长度和str2的长度是否相等
            //如是进入核心算法
            char v1[] = value;                   //v1为当前对象str1的值,v2为参数对象str2的值
            char v2[] = anotherString.value;
            int i = 0;                           //就类似于for的int i =0的作用,因为这里使用while
            while (n-- != 0) {                   //每次循环长度-1,直到长度消耗完,循环结束 
                if (v1[i] != v2[i])              //同索引位置的字符元素逐一比较
                    return false;                //只要有一个不相等,则返回false
                i++;
            }
            return true;                         //如比较期间没有问题,则说明相等,返回true
        }
    }
    return false;
}

31、equalsIgnoreCase

/**
* 这也是一个String的equals方法,与上一个方法不用,该方法(不区分大小写),从名字也能看出来
* 是对String的equals方法的补充。
* 这里参数这是一个String对象,而不是Object了,因为这是String本身的方法,不是重写谁的方法
*/
public boolean equalsIgnoreCase(String anotherString) {
    return (this == anotherString) ? true                   //一样,先判断是否为同一个对象
            : (anotherString != null) 
            && (anotherString.value.length == value.length) //再判断长度是否相等
            && regionMatches(true, 0, anotherString, 0, value.length);  //再执行regionMatchs方法 
}
  • equalsIgnoreCase()方法是对equals()方法补充,不区分大小写的判断

32、contentEquals方法

/**
* 这是一个公有的比较方法,参数是StringBuffer类型
* 实际调用的是contentEquals(CharSequence cs)方法,可以说是StringBuffer的特供版
*/
public boolean contentEquals(StringBuffer sb) {
    return contentEquals((CharSequence)sb);
}

/**
* 这是一个私有方法,特供给比较StringBuffer和StringBuilder使用的。
* 比如在contentEquals方法中使用,参数是AbstractStringBuilder抽象类的子类
*
*/
private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
    char v1[] = value;			//当前String对象的值
    char v2[] = sb.getValue();	//AbstractStringBuilder子类对象的值
    int n = v1.length;			//后面就不说了,其实跟equals方法是一样的,只是少了一些判断
    if (n != sb.length()) {
        return false;
    }
    for (int i = 0; i < n; i++) {
        if (v1[i] != v2[i]) {
            return false;
        }
    }
    return true;
}

/**
* 这是一个常用于String对象跟StringBuffer和StringBuilder比较的方法
* 参数是StringBuffer或StringBuilder或String或CharSequence
* StringBuffer和StringBuilder和String都实现了CharSequence接口
*/
public boolean contentEquals(CharSequence cs) {
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {	//如果是AbstractStringBuilder抽象类或其子类
            if (cs instanceof StringBuffer) {		//如果是StringBuffer类型,进入同步块
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {		 //如果是StringBuilder类型,则进入非同步块
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }
    /***下面就是String和CharSequence类型的比较算法*****/
        // Argument is a String
        if (cs instanceof String) {
            return equals(cs);
        }
        // Argument is a generic CharSequence
        char v1[] = value;
        int n = v1.length;
        if (n != cs.length()) {
            return false;
        }
        for (int i = 0; i < n; i++) {
            if (v1[i] != cs.charAt(i)) {
                return false;
            }
        }
        return true;
    }
  • contentEquals()则是用于String对象与4种类型的判断,通常用于跟StringBuilder和StringBuffer的判断,也是对equals方法的一个补充

33、regionMatchs()方法

/**
* 这是一个类似于equals的方法,比较的是字符串的片段,也即是部分区域的比较
* toffset是当前字符串的比较起始位置(偏移量),other是要比较的String对象参数,ooffset是要参数String的比较片段起始位置,len是两个字符串要比较的片段的长度大小
* 
* 例子:String str1 = "0123456",Str2 = "0123456789"; 
* str1.regionMatchs(0,str2,0,6);意思是str1从0位置开始于str2的0位置开始比较6个长度的字符串片段
* 相等则返回 true,不等返回false 
*/
public boolean regionMatches(int toffset, String other, int ooffset,
        int len) {
    char ta[] = value;		//当前对象的值
    int to = toffset;		//当前对象的比较片段的起始位置,既偏移量
    char pa[] = other.value;	//参数,既比较字符串的值
    int po = ooffset;		 //比较字符串的起始位置
    // Note: toffset, ooffset, or len might be near -1>>>1.
    if ((ooffset < 0) || (toffset < 0)//起始位置不小于0或起始位置不大于字符串长度 - 片段长度,大于就截取不到这么长的片段了
            || (toffset > (long)value.length - len)
            || (ooffset > (long)other.value.length - len)) {
        return false;	//惊讶脸,居然不是抛异常,而是返回false
    }
    while (len-- > 0) {		 //使用while循环,当然也可以使for循环
        if (ta[to++] != pa[po++]) {		//片段区域的字符元素逐个比较
            return false;
        }
    }
    return true;
}


/**
* 这个跟上面的方法一样,只不过多了一个参数,既ignoreCase,既是否为区分大小写。
* 是equalsIgnoreCase()方法的片段比较版本,实际上equalsIgnoreCase()也是调用regionMatches函数
*/
 public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        char ta[] = value;
        int to = toffset;
        char pa[] = other.value;
        int po = ooffset;
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;
        }
        while (len-- > 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            if (c1 == c2) {
                continue;
            }
            if (ignoreCase) {
                // If characters don't match but case may be ignored,
                // try converting both characters to uppercase.
                // If the results match, then the comparison scan should
                // continue.
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                if (u1 == u2) {
                    continue;
                }
                // Unfortunately, conversion to uppercase does not work properly
                // for the Georgian alphabet, which has strange rules about case
                // conversion.  So we need to make one last check before
                // exiting.
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }
            return false;
        }
        return true;
    }

34、compareTo类函数和CaseInsensitiveComparator静态内部类

/**
	* 这是一个比较字符串中字符大小的函数,因为String实现了Comparable<String>接口,所以重写了compareTo方法
	* Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。
	* 实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
	* 
	* 参数是需要比较的另一个String对象
	* 返回的int类型,正数为大,负数为小,是基于字符的ASSIC码比较的
	* 
	*/
	public int compareTo(String anotherString) {
        int len1 = value.length;                  //当前对象的长度
        int len2 = anotherString.value.length;    //比较对象的长度
        int lim = Math.min(len1, len2);           //获得最小长度
        char v1[] = value;                        //获得当前对象的值
        char v2[] = anotherString.value;          //获得比较对象的值
int k = 0;                                //相当于for的int k = 0,就是为while循环的数组服务的
    while (k < lim) {                         //当当前索引小于两个字符串中较短字符串的长度时,循环继续
        char c1 = v1[k];          //获得当前对象的字符
        char c2 = v2[k];          //获得比较对象的字符
        if (c1 != c2) {           //从前向后遍历,只要其实一个不相等,返回字符ASSIC的差值,int类型
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;           //如果两个字符串同样位置的索引都相等,返回长度差值,完全相等则为0
}

/**
*  这时一个类似compareTo功能的方法,但是不是comparable接口的方法,是String本身的方法
*  使用途径,我目前只知道可以用来不区分大小写的比较大小,但是不知道如何让它被工具类Collections和Arrays运用
*
*/
public int compareToIgnoreCase(String str) {
    return CASE_INSENSITIVE_ORDER.compare(this, str);
}

/**
* 这是一个饿汉单例模式,是String类型的一个不区分大小写的比较器
* 提供给Collections和Arrays的sort方法使用
* 例如:Arrays.sort(strs,String.CASE_INSENSITIVE_ORDER);
* 效果就是会将strs字符串数组中的字符串对象进行忽视大小写的排序
*
*/
public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                     = new CaseInsensitiveComparator();

/**
* 这一个私有的静态内部类,只允许String类本身调用
* 实现了序列化接口和比较器接口,comparable接口和comparator是有区别的
* 重写了compare方法,该静态内部类实际就是一个String类的比较器
*
*/
private static class CaseInsensitiveComparator
        implements Comparator<String>, java.io.Serializable {
    // use serialVersionUID from JDK 1.2.2 for interoperability
    private static final long serialVersionUID = 8575799808933029326L;

    public int compare(String s1, String s2) {
        int n1 = s1.length();                 //s1字符串的长度
        int n2 = s2.length();                 //s2字符串的长度
        int min = Math.min(n1, n2);           //获得最小长度 
        for (int i = 0; i < min; i++) {
            char c1 = s1.charAt(i);           //逐一获得字符串i位置的字符
            char c2 = s2.charAt(i);
            if (c1 != c2) {                   //部分大小写比较一次
                c1 = Character.toUpperCase(c1);    //转换大写比较一次
                c2 = Character.toUpperCase(c2);
                if (c1 != c2) {
                    c1 = Character.toLowerCase(c1);  //转换小写比较一次
                    c2 = Character.toLowerCase(c2);
                    if (c1 != c2) {                  //返回字符差值
                        // No overflow because of numeric promotion
                        return c1 - c2;
                    }
                }
            }
        }
        return n1 - n2;  //如果字符相等,但是长度不等,则返回长度差值,短的教小,所以小-大为负数
    }

    /** Replaces the de-serialized object. */
    private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}

以上的代码可以看出:

以上的最大问题可以能就是为什么要有个静态内部类,为什么实现了compareTo又有compare,移步到下面,有解答

String实现了comparable接口,重写了compareTo方法,可以用于自己写类进行判断排序,也可以使用collections,Arrays工具类的sort进行排序。只有集合或数组中的元素实现了comparable接口,并重写了compareTo才能使用工具类排序。

 //返回字符差值
                    // No overflow because of numeric promotion
                    return c1 - c2;
                }
            }
        }
    }
    return n1 - n2;  //如果字符相等,但是长度不等,则返回长度差值,短的教小,所以小-大为负数
}

/** Replaces the de-serialized object. */
private Object readResolve() { return CASE_INSENSITIVE_ORDER; }

}


以上的代码可以看出:

以上的最大问题可以能就是为什么要有个静态内部类,为什么实现了compareTo又有compare,移步到下面,有解答

String实现了comparable接口,重写了compareTo方法,可以用于自己写类进行判断排序,也可以使用collections,Arrays工具类的sort进行排序。只有集合或数组中的元素实现了comparable接口,并重写了compareTo才能使用工具类排序。

- `CASE_INSENSITIVE_ORDER`是一个单例,是String提供为外部的比较器,该比较器的作用是忽视大小写进行比较,我们可以通过Collections或Arrays的sort方法将CASE_INSENSITIVE_ORDER比较器作为参数传入,进行排序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值