String源码解析

2022-07-27,,

本章源码分析基于JDK1.7

实现的接口

String类被final修饰词修饰,代表不可修改的特性,它实现了三个接口,Serializable是序列化接口,Compareble是排序接口,Char是字符序列接口。

public final class String implements Serializable, Comparable<String>, CharSequence 

主要成员变量

char[]:String通过char[]来实现String的各种功能,字符串由字符数组实现。

hash:用于缓存hash值,因为String类是final不可修改的,所以hash值也是固定的,为了避免重复计算hash值而缓存。

CASE_INSENSITIVE_ORDER:排序器,由上可知String类实现了Compareble接口,这里的Comparator用于忽视大小写的字符串的比较。

    private final char[] value;
    private int hash;
    public static final Comparator<String> CASE_INSENSITIVE_ORDER = new String.CaseInsensitiveComparator();

构造函数

String共有15个重载构造函数,入参这几种:空、char[]、String、StringBuffer、StringBuilder、byte[],通过这些来构造字符串对象。

    //第一种,入参为空,新建了大小为0的char数组,这就是空字符串
    public String() {
        this.hash32 = 0;
        this.value = new char[0];
    }

    //第二种,入参为String对象,直接将入参的属性复制过来
    public String(String var1) {
        this.hash32 = 0;
        this.value = var1.value;
        this.hash = var1.hash;
    }

    //第三种,入参为char[],将value赋值为入参var1
    public String(char[] var1) {
        this.hash32 = 0;
        this.value = Arrays.copyOf(var1, var1.length);
    }

    //第四种,入参为char[],截取char[]中从var2到var3的字符作为字符串
    public String(char[] var1, int var2, int var3) {
        this.hash32 = 0;
        if (var2 < 0) {
            throw new StringIndexOutOfBoundsException(var2);
        } else if (var3 < 0) {
            throw new StringIndexOutOfBoundsException(var3);
        } else if (var2 > var1.length - var3) {
            throw new StringIndexOutOfBoundsException(var2 + var3);
        } else {
            this.value = Arrays.copyOfRange(var1, var2, var2 + var3);
        }
    }

    
    public String(int[] var1, int var2, int var3) {
        this.hash32 = 0;
        if (var2 < 0) {
            throw new StringIndexOutOfBoundsException(var2);
        } else if (var3 < 0) {
            throw new StringIndexOutOfBoundsException(var3);
        } else if (var2 > var1.length - var3) {
            throw new StringIndexOutOfBoundsException(var2 + var3);
        } else {
            int var4 = var2 + var3;
            int var5 = var3;

            int var7;
            for(int var6 = var2; var6 < var4; ++var6) {
                var7 = var1[var6];
                if (!Character.isBmpCodePoint(var7)) {
                    if (!Character.isValidCodePoint(var7)) {
                        throw new IllegalArgumentException(Integer.toString(var7));
                    }

                    ++var5;
                }
            }

            char[] var10 = new char[var5];
            var7 = var2;

            for(int var8 = 0; var7 < var4; ++var8) {
                int var9 = var1[var7];
                if (Character.isBmpCodePoint(var9)) {
                    var10[var8] = (char)var9;
                } else {
                    Character.toSurrogates(var9, var10, var8++);
                }

                ++var7;
            }

            this.value = var10;
        }
    }

    /** @deprecated */
    @Deprecated
    public String(byte[] var1, int var2, int var3, int var4) {
        this.hash32 = 0;
        checkBounds(var1, var3, var4);
        char[] var5 = new char[var4];
        int var6;
        if (var2 == 0) {
            for(var6 = var4; var6-- > 0; var5[var6] = (char)(var1[var6 + var3] & 255)) {
                ;
            }
        } else {
            var2 <<= 8;

            for(var6 = var4; var6-- > 0; var5[var6] = (char)(var2 | var1[var6 + var3] & 255)) {
                ;
            }
        }

        this.value = var5;
    }

    /** @deprecated */
    @Deprecated
    public String(byte[] var1, int var2) {
        this(var1, var2, 0, var1.length);
    }

    private static void checkBounds(byte[] var0, int var1, int var2) {
        if (var2 < 0) {
            throw new StringIndexOutOfBoundsException(var2);
        } else if (var1 < 0) {
            throw new StringIndexOutOfBoundsException(var1);
        } else if (var1 > var0.length - var2) {
            throw new StringIndexOutOfBoundsException(var1 + var2);
        }
    }

    public String(byte[] var1, int var2, int var3, String var4) throws UnsupportedEncodingException {
        this.hash32 = 0;
        if (var4 == null) {
            throw new NullPointerException("charsetName");
        } else {
            checkBounds(var1, var2, var3);
            this.value = StringCoding.decode(var4, var1, var2, var3);
        }
    }

    public String(byte[] var1, int var2, int var3, Charset var4) {
        this.hash32 = 0;
        if (var4 == null) {
            throw new NullPointerException("charset");
        } else {
            checkBounds(var1, var2, var3);
            this.value = StringCoding.decode(var4, var1, var2, var3);
        }
    }

    public String(byte[] var1, String var2) throws UnsupportedEncodingException {
        this(var1, 0, var1.length, (String)var2);
    }

    public String(byte[] var1, Charset var2) {
        this(var1, 0, var1.length, (Charset)var2);
    }

    public String(byte[] var1, int var2, int var3) {
        this.hash32 = 0;
        checkBounds(var1, var2, var3);
        this.value = StringCoding.decode(var1, var2, var3);
    }

    public String(byte[] var1) {
        this((byte[])var1, 0, var1.length);
    }

    public String(StringBuffer var1) {
        this.hash32 = 0;
        synchronized(var1) {
            this.value = Arrays.copyOf(var1.getValue(), var1.length());
        }
    }

    public String(StringBuilder var1) {
        this.hash32 = 0;
        this.value = Arrays.copyOf(var1.getValue(), var1.length());
    }

    String(char[] var1, boolean var2) {
        this.hash32 = 0;
        this.value = var1;
    }

    /** @deprecated */
    @Deprecated
    String(int var1, int var2, char[] var3) {
        this(var3, var1, var2);
    }

length方法

通过获取char[]的长度来获取字符串的长度

    public int length() {
        return this.value.length;
    }

isEmpty方法

通过判断char[]的长度是否为0来判断是否为空

    public boolean isEmpty() {
        return this.value.length == 0;
    }

charAt方法

通过char[]数组下标获取到对应位置的char字符

    public char charAt(int var1) {
        if (var1 >= 0 && var1 < this.value.length) {
            return this.value[var1];
        } else {
            throw new StringIndexOutOfBoundsException(var1);
        }
    }

equals方法

首先比较内存地址,再判断是否是String类型,然后再判断长度,最后逐个比较其中的char。

    public boolean equals(Object var1) {
        //首先比较内存地址
        if (this == var1) {
            return true;
        } else {
            //判断var1是否是String类型
            if (var1 instanceof String) {
                //如果是则强转
                String var2 = (String)var1;
                //获取当前String中char[]的长度
                int var3 = this.value.length;
                //如果传入的var1和当前String中char[]的长度一样
                if (var3 == var2.value.length) {
                    
                    char[] var4 = this.value;
                    char[] var5 = var2.value;
                    //将传入的var1和当前字符串中char[]中字符逐个比较,若有一个不一致则返回false
                    for(int var6 = 0; var3-- != 0; ++var6) {
                        if (var4[var6] != var5[var6]) {
                            return false;
                        }
                    }

                    return true;
                }
            }

            return false;
        }
    }

hashCode方法

这里的hash值计算有个特点,就是String内部缓存了hash值,如果hash值不为0则直接返回,不需要再次进行计算,因为String是被final修饰的,它不会被修改,所以没有必要每次都重新计算hash值。

    public int hashCode() {
        //首先从String的成员变量hash获取到hash值
        int var1 = this.hash;
        //如果hash值为0且当前String不为空
        if (var1 == 0 && this.value.length > 0) {
            //获取到当前String的char[]
            char[] var2 = this.value;

            //逐个使用char循环叠加计算hash值
            for(int var3 = 0; var3 < this.value.length; ++var3) {
                var1 = 31 * var1 + var2[var3];
            }

            //计算好后将hash值赋值给成员变量hash
            this.hash = var1;
        }

        //最后返回hash值
        return var1;
    }

compareTo方法

通过两个字符串的第一个不一样的字符来比较大小并返回结果,若两个字符串的字符都一样则比较两个字符串的长度。

    public int compareTo(String str) {
        //分别获取到当前String和传入String的length
        int thisLen = this.value.length;
        int strLen = str.value.length;
        //计算出两个String最小的长度minLen
        int minLen = Math.min(thisLen, strLen);
        char[] thisValue = this.value;
        char[] strValue = str.value;

        //循环找出两个字符串第一个不一样的字符比较大小并返回比较结果
        for(int i = 0; i < minLen; ++i) {
            char thisChar = thisValue[i];
            char strChar = strValue[i];
            if (thisChar != strChar) {
                return thisChar - strChar;
            }
        }
    
        //若两个字符串循环比较的字符是一样的,那么使用字符串长度来比较大小
        return thisLen - strLen;
    }

 

本文地址:https://blog.csdn.net/w8827130/article/details/88932467

《String源码解析.doc》

下载本文的Word格式文档,以方便收藏与打印。