0
点赞
收藏
分享

微信扫一扫

Java 字符串类String的底层解析

无愠色 2022-03-22 阅读 51

1. String是如何实现的?它有哪些方法

  • String类被final修饰,表明此类不能被继承,其中的方法也都是final类型;
  • String类型实现了Serializable, Comparable, CharSequence接口;
  • String类的值是通过char型数组存放,并且被private和final修饰,表明字符串一旦创建不能修改;

实现:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
            //final修饰的char型数组存储字符串值
            private final char value[];
            //缓存字符串的hashcode
            private int hash;
            //....其他内容
        }

方法:

1) 多构造方法

1)String为参数的构造方法
            public String(String original) {
                this.value = original.value;
                this.hash = original.hash;
            }2char[]为参数的构造方法
            public String(char[] value) {
                this.value = Arrays.copyOf(value,value.length);
            }3)StringBuffer为参数的构造方法
            public String(StringBuffer buffer) {
                synchronized(buffer){
                    this.value = Arrays.copyOf(buffer.getValue(),buffer.length());
                }
            }4)StringBuilder为参数的构造方法
            public String(StringBuilder builder) {
                 this.value = Arrays.copyOf(builder.getValue(),builder.length());
            }

2) equals()比较两个字符串相等

            String类重写了Object类型中的equals()方法,比较的是内容
            public boolean equals(Object anObject) {
                //对象引用相同直接返回true
                if(this == anObject){   //==对于引用数据类型比较引用地址
                    return true;
                }
                //判断需要对比的值是否是String类型,如果不是则直接返回false
                if(anObject instanceof String){ //使用instanceof关键字判断是否属于String类型
                    String anotherString = (String)anObject;
                    int n = value.length;
                    //判断二者长度是否一致,不一致返回false
                    if(n == anotherString.value.length){
                        //把两个字符串都转换为char数组对比
                        char v1[] = value;
                        char v2[] = anotherString.value;
                        int i = 0;
                        //循环对比两个字符串的每一个字符
                        while(n-- != 0){
                            //如果其中有一个不相等就返回false,否则继续对比
                            if(v1[i] != v2[i]){
                                return false;
                            }
                            i++;
                        }
                        return true;
                    }
                }
                return false;
            }
                补充:instanceof 使用
                Object oString = "123";
                Object oInt = 123;
                System.out.println(oString instanceof String);  //true
                System.out.println(oInt instanceof String); //false

3) compareTo()比较两个字符串,返回-1,0,1

public int compareTo(String anotherString){
                int len1 = value.length;
                int len2 = anotherString.value.length;
                //获取两个字符串长度最短的那个int值
                int lim = Math.min(len1, len2);
                char v1[] value;
                char v2[] anotherString.value;
                int k = 0;
                //对比每一个字符
                while(k<lim){
                    char c1 = v1[k];
                    char c2 = v2[k];
                    if(c1 != c2){
                    //如果字符不相等,就返回c1-c2,结果有-1,1
                        return c1 - c2;
                    }
                    k++;
                }
                return len1 - len2;
            }
                补充:与equals()的不同
                - equals()可以接受Object类型参数,compareTo()只能接受String类型参数
                - equals()返回类型是booleancompareTo()返回值类型是int

4) 其他方法

 			indexOf();
            lastIndexOf();
            contains();
            toLowerCase();
            length();
            trim();
            replace();  //replace没有在原字符串上修改,而是另外创建了一个字符串
            split();
            join(); //把字符串数组转为字符串

2. String类为什么要用final修饰?

    1) - 安全性:
        因为字符串是不可变的,所以多线程是安全的,同一个字符串可以被多个线程共享
        不必额外做同步操作;
        String类被许多java类当作参数,如url,文件路径path等,如果可变就会产生安全隐患。
    2) - 效率
        字符串不变保证了hash码的唯一,可以放心的进行缓存;
        只有字符串不变,字符串常量池才可以实现,
        当创建一个String对象时,当此串值已存在于常量池中,就不会再创建新的对象,而是引用已存在的对象。

3. 字符串常量池?

JVM为了提高系能减小内存开销,在实例化字符串时用字符串常量池进行优化;
        当创建字符串时,JVM会首先检查字符串常量池,如果该字符串已存在于池中,那么就直接返回池中的实例引用;
        如果池中不存在,就会实例化该字符串并放到池中。
    
        补充:new String("abc")创建了几个对象?
            一个或两个
            如果"abc"之前没使用过,就会创建两个对象,堆中创建一个,字符串常量池创建一个;
            如果之前用过,只会在堆中创建一个。

4. 字符串拼接?

在循环内拼接字符串使用 += 会出现问题
        String的 += 底层实际使用的是StringBuilder,然后用append()拼接,最后调用toString()赋值给String对象;
        循环内拼接建议用StringBuilder或StringBuffer。

附:哔哩哔哩视频地址

举报

相关推荐

0 条评论