欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

String源码解析

程序员文章站 2022-05-04 08:43:00
本章源码分析基于JDK1.7实现的接口String类被final修饰词修饰,代表不可修改的特性,它实现了三个接口,Serializable是序列化接口,Compareble是排序接口,Char是字符序列接口。public final class String implements Serializable, Comparable, CharSequence......

本章源码分析基于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