JAVA之String源码(基于jdk1.8)

这是一个flag!

 

新手小白对于源码的困惑!

  做初级开发的时候知道有源码,可是从来不会去主动看,因为工作上压根用不到,而且源码的注释全部是英文的,看起来压力比较大,头疼,每次一看见英文注释就跳过,心理默念,这段代码跟自己没关系100遍。

  近期感觉自己在业务上无法得到提高,对原来的这些基础代码抱着很大的兴趣,慢慢的来看一些源码功能!

  看了几篇文章,结合自己对于源码的理解之后,梳理出自己的逻辑和看源码的方式!

  1.对于简单的类说,例如基础的String,Integer等 ,你要把它理解为一个个体,就像一个Person类,他是一个人的抽象类,那他有哪些人的特征,那它就有哪些人的属性,String类呢,他的底层结构是一个char类型的数组,所以他有了value这个属性

private final char value[];

 

  2.除了一些属性之外,String这个类被创造出来肯定是要用来实现一些功能的,例如你创建一个人出来,不会只是想着这个人就放在那啥也不干吧,于是我们就会给他赋予各种功能,这些功能就是我们说的类里面的方法。例如String类里面的构造方法,作为一个“生孩子”的手段,构造方法承担了太多,以至于我们要采用各种“外科手术”,见下图

  总结:根据以上两点来说,java面向对象的思想都是基于抽象类来进行的,类,代表着个体,生态,功能,循环,有了类的抽象,一切都是类自身与类功能的组合,借用,其中涉及的各方面的功能实现都是其中为了满足构建类生态能够完美运行的设计精密的细节。在看源码的过程中,我也要本着全局观的视角来一一验证我的上述猜想!

flag实现之1:String源码

  1.String历史由来

  2.String的属性介绍

  3.String的构造方法

  4.String的其他方法

  

  1.String的历史由来

    String字符这种类型由来已久,在C++语言中,他就是字符串模板类的实例,而java从C++语言中吸收了各种优秀的语言设计思想之后诞生,故而,String这个类型可能是开发者的习惯或者是方便与大众接受等原因,沿用了C++中string>头文件的标识

  2.String的属性介绍

    (1) value属性

      String字符串作为一个存储字符序列的类型,他的底层实现必定是字符实现才对,所以String具有 char value[] 属性,它的实现就是将一个个char字符拼接起来,组成一个有顺序的数组,这样我们在使用String的对象时就能拿出一个有序的字符串;

      String字符串的value属性被final修饰了。意味着String类不可变,那么为什么会设置成不可变呢,这主要是为了安全性和效率性的考虑,我找到了一位老兄的解答,说的很有趣,特此借鉴

                    

    (2) hash属性

      hash属性用来缓存字符串的哈希码,哈希码的作用主要是用于查找的快捷性,散列存储结构中确定存储对象的存储地址的,两个对象的hash值相同,他们不一定是一个对象,只能说明他们在同一个散列的存储结构中,也就是“同一个篮子里”。而当两个对象相同,那么肯定适用于equals方法,那么他们的hashcode值一定相同,如果equals方法被重写,那么hashCode方法最好也尽量重写

    (3) serialVersionUID属性

      serialVersionUID属性适用于java序列化机制,java序列化机制通过判断类的serialVersionUID是否相同来判断版本是否一致。在进行反序列化时,如果JVM传过来的字节流汇总的serialVersionUID与本地类中的serialVersionUID进行比较,一致则进行反序列化,不一致,则出现异常,InvalidCastException。

    (4) serialPersistentFields[]属性

      这个属性是指定默认哪些字段要被序列化,和transient相反,transient修饰的属性申明不需要被序列化,当两者同时存在的时候,transient会被忽略。

    (5) CASE_INSENSITIVE_ORDER

       java的String类忽略大小写敏感比较器,主要是在compareToIgnoreCase(String str)方法中需要使用到。

  3.String的构造方法

    String的源码中有16中构造方法,有些方法已经过时不被建议调用,其中就有两项使用@Deprecated修饰

    (1)  String(byte [], int, int, int)和String(byte[], int)方法已经被不推荐使用,这两个方法的官方说明如下

String(byte[] ascii, int hibyte, int offset, int count)
已弃用
此方法无法将字节正确转换为字符。 从JDK 1.1开始,首选的方式是通过String构造函数获取Charset ,字符集名称,或使用平台的默认字符集。

String(byte[] ascii, int hibyte)
已弃用
此方法无法将字节正确转换为字符。 从JDK 1.1开始,首选的方法是通过String构造函数获取Charset ,字符集名称,或者使用平台的默认字符集。

    (2)其他的构造方法

    无参构造:String(),默认值是一个空的字符串数组;

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

    单个参数构造:①String(String original),②String(char value[]),③String(byte bytes[]),④String(StringBuffer buffer),⑥String(StringBuilder builder)

    第一种就是直接将原来的String对象的value和hash值复制到新的String对象中,第二种是直接将value数组复制到新的String对象value里面,第三种是将byte数组复制到value值中,内部其实是调用了String(byte bytes[], int offset, int length)方法来使用默认的字符集解码byte数组构造新的String对象,第四第五种只是在第二种方法上增加了一层转化,兼容两种String的工具类对象初始化String

    多个参数构造:

    String(char value[], int offset, int count):此方法获取value数组从第offset为开始节点,长度为count的数组,赋值给value,构造成新的String对象

    String(int[] codePoints, int offset, int count):此方法是将int型的数据转化成char数组并且根据offset和count初始化新的String对象

    String(byte bytes[], int offset, int length, String charsetName):此方法是将bytes数组根据传入的字符集名称转化成char数组并且根据offset和count初始化String对象

    String(byte bytes[], int offset, int length, Charset charset):同上,只是此方法是根据java内置的字符集类型进行初始化

    以下几种方法与上面大同小异,只是入参稍有不同

String(byte bytes[], String charsetName)
String(byte bytes[], Charset charset)
String(byte bytes[], int offset, int length)
String(char[] value, boolean share)

    在String的构造方法中多次调用checkBounds(byte[] bytes, int offset, int length)方法,主要是为了防止在对byte[] 做截取的时候发生数组下标越界问题,此为校验方法,当传入的初始化参数不正确,将会抛出StringIndexOutOfBoundsException异常。

  4.String的其他方法

    String内部的处理字符串的方法很多,我们需要按照它内部实现的功能来进行分类,功能类似的方法可以放在一起看:

    (1)校验类方法:

      checkBounds(byte[] bytes, int offset, int length):检查传入的截取参数和字符数组是否有下标越界的错误

      length():检查字符串长度的方法,返回value数组的length属性

      isEmpty():检查字符串是否为空字符串的方法,根据value.length == 0 来判断,所以,“”这种空串也是会返回true的

    (2)获取字符值或者字符数组值,字节数组值方法:

      charAt(int index):获取字符串对象第index位上的字符值,也就是value[index]的值

      codePointBefore(int index):获取字符串对象第index前一位上的字符值,也就是value[index-1]的值

      codePointAt(int index):获取String对象的index下标处字符的ASCII值

      codePointCount(int beginIndex, int endIndex):获取String字符串对象从beginIndex(包含)到endIndex(不包含)中间Unicode代码点数

      offsetByCodePoints(int index, int codePointOffset):获取String字符串对象从index开始偏移codePointOffset位的Unicode代码点数

      getChars(char dst[], int dstBegin):将字符数组复制到目标字符数组中,从目标数组的dstBegin位置开始,返回字符串(因为数组不会自动扩容,所以这里很容易造成字符数组下标越界)

      getChars(int srcBegin, int srcEnd, char dst[], int dstBegin):同上,只是指定了要复制的字符串从srcBegin(包含)开始,到srcEnd(不包含)结束

      getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin):此方法功能同上,只是目前已废弃,不推荐使用

      getBytes(String charsetName):获取指定名称的编码格式字节数组值

      getBytes(Charset charset):同上,只是使用了java自带的编码格式类型

      getBytes():获取默认编码类型的字节数组值

      hashCode():获取哈希码,如果当前哈希码是0且长度不为0的话,则重新计算正确的哈希码

    (3)比较,匹配类方法:

      equals(Object anObject):直接通过“==”进行比较,如果是同一个对象,则相等,否则将Object  数组转化成char数组来进行字符比较(关于String的equals方法,如果是两个String字符串比较会有很多有趣的内容,大家可以自己深究一下)

      contentEquals(CharSequence cs):提供对StringBuilder和StringBuffer,String三种类型的内容匹配功能,StringBuffer类型会被加同步锁,防止在比对的过程中对该对象做修改,StringBuilder则调用nonSyncContentEquals方法,String对象则调用equals方法

      contentEquals(StringBuffer sb):提供对StringBuilder对象的比较,实现调用的是上面方法,只是将StringBuilder类型强转成CharSequence 类型对象而已

      equalsIgnoreCase(String anotherString):忽略大小写的比较方式,内部调用了regionMatches(boolean ignoreCase, int toffset,String other, int ooffset, int len)方法,可以按照选定的区域匹配忽略大小写的字符串是否相同

      regionMatches(int toffset, String other, int ooffset,int len):不忽略大小写,按照选定区域匹配字符串是否相同

      regionMatches(boolean ignoreCase, int toffset,String other, int ooffset, int len):可以按照选定的区域匹配忽略大小写的字符串是否相同

      startsWith(String prefix):匹配当前字符串是否以prefix开头,是则返回true,否则返回false

      startsWith(String prefix, int toffset):同上,可以指定开头匹配的下标toffset

      endsWith(String suffix):奇妙的一个方法,竟然调用的是startsWith(String prefix, int toffset)方法,程序员的逻辑果然深不可测,佩服佩服

      indexOf(int ch):查找当前字符串中是否存在int型数字,有则返回该元素的下标,没有则返回-1

      indexOf(int ch, int fromIndex):同上,只是指定了开始检索的开始下标fromIndex

      indexOfSupplementary(int ch, int fromIndex):用来被上面方法调用,当传入的匹配字符大于等于最小的补码时调用,会通过高位补码和低位补码一起匹配

      lastIndexOf(int ch):原理同indexOf(int ch)方法,只是比较的过程是从大索引往小索引遍历匹配

      lastIndexOf(int ch, int fromIndex):同上,只是可以指定开始检索的开始下标fromIndex

      lastIndexOfSupplementary(int ch, int fromIndex):同上,也是可以指定开始检索的开始下标fromIndex

      indexOf(String str):匹配字符串,对被匹配的字符数组进行循环遍历,根据字符串的长度计算出匹配的开始和结束下标,在此下标范围内进行字符匹配,完全一致则返回字符串的开始下标

      indexOf(String str, int fromIndex):同上,可以指定开始匹配的开始下标fromIndex

      indexOf(char[] source, int sourceOffset, int sourceCount,String target, int fromIndex):被上面方法调用

      indexOf(char[] source, int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex):同上,只是将匹配的字符串改为了char数组

      lastIndexOf(String str)

      lastIndexOf(String str, int fromIndex)

      lastIndexOf(char[] source, int sourceOffset, int sourceCount,String target, int fromIndex):以上三个方法和上面的indexOf方法基本原理一样,只是将正向遍历的匹配方式改成了逆向遍历匹配而已

    (4)操作类方法:

      substring(int beginIndex):截取字符串,从beginIndex下标开始,如果等于0则返回原来的字符串,如果不是,则新new一个字符串

      substring(int beginIndex, int endIndex):截取字符串,从beginIndex下标开始,到endIndex结束,如果beginIndex等于0且endIndex等于value.length,则返回原来的字符串,如果不是,则新new一个字符串

      subSequence(int beginIndex, int endIndex):同上,只是返回的类型不是String,而是CharSequence

      concat(String str):拼接字符串,如果拼接的字符串的长度为0,则返回原来的字符串,如果不,则返回一个新new的拼接字符串

      replace(char oldChar, char newChar):替换字符串内所有的老字符oldChar为新字符newChar,如果新老字符一样,则不作操作,返回原来的字符,如果不一样,则返回新new的替换字符串

      matches(String regex):该方法是调用的正则类做全匹配,当两个字符串一样的时候返回true,否则返回false

      contains(CharSequence s):此方法调用的是indexOf(String str)方法,当能够匹配到字符对象s的时候返回大于-1的值,否则返回-1

      replaceFirst(String regex, String replacement):此方法调用的是正则匹配类的replaceFirst(String replacement)方法,将源字符串中的第一个regex字符串替换为新的replacement字符串

      replaceAll(String regex, String replacement):原理同上,只是替换所有匹配到的regex字符串

      replace(CharSequence target, CharSequence replacement):同上,只是采用了不同的方法进行替换

      split(String regex, int limit):在limit(包括limit)范围内匹配regex,匹配到则分隔为一个元素,匹配到几个分割位 几个元素,limit后面的元素不分割,返回分割的数组返回

      split(String regex):同上,只是默认limit为0,及不做限制,对整个字符串进行匹配分割

      join(CharSequence delimiter, CharSequence... elements):

      join(CharSequence delimiter,Iterable<? extends CharSequence> elements):以上两个方法都是调用StringJoiner的join方法,一个提供的是多元素入参,一个提供的是数组入参而已

      toLowerCase(Locale locale):将字符串中的字母全部转化为小写字母,使用指定的local对象

      toLowerCase():将字符串中的字母全部转化为小写字母,使用默认的local对象

      toUpperCase(Locale locale):将字符串中的字母全部转化为大写字母,使用指定的local对象

      toUpperCase():将字符串中的字母全部转化为大写字母,使用默认的local对象

      trim():此方法是通过校验字符数组的每一个值是否<=“”,是则忽略,否,则调用substring(int beginIndex, int endIndex)方法,截取不为空的节点为新的字符串

      toString():String字符串的toString()方法直接返回的是他自身

      toCharArray():新建了一个char数组,并且将value复制了一份到新的char数组中返回

      format(String format, Object... args):这里调用的是Formatter类的format方法,这个方法可以根据指定不同的参数类型来对字符串进行占位,对数字类型进行进制计算等格式化操作

      format(Locale l, String format, Object... args):同上,只是增加了指定的locale对象

      valueOf(Object obj):将object对象转换成String字符串

      valueOf(char data[]):将char数组转换成String字符串

      valueOf(char data[], int offset, int count):将char数组转换成String字符串,并且指定了开始下标和偏移量

      copyValueOf(char data[], int offset, int count):同上,只是名称不一样,内部方法一致

      copyValueOf(char data[]):将整个char数组转换成String字符串

      valueOf(boolean b):将boolean类型变量转换成String字符串,返回true或者false

      valueOf(char c):将char字符转换成字符串输出

      valueOf(int i):将int类型变量转换成String字符串对象,调用的是Integer.toString()方法

      valueOf(long l):将long类型变量转换成String字符串对象,调用的是Long.toString()方法

      valueOf(float f):将float 类型变量转换成String字符串对象,调用的是Float.toString()方法

      valueOf(double d):将double 类型变量转换成String字符串对象,调用的是Double.toString()方法

      intern():此方法是由native修饰的本地方法,用以扩充常量池,如果常量池中不存在当前字符串对象,则会复制一个副本保存到常量池,并且将常量池汇总的引用返回

 

flag结束,我TM以前从来没想过String具有如此之多的方法,差点心态炸裂!!!

posted @ 2021-07-05 15:39  书山有路春风生  阅读(642)  评论(0)    收藏  举报