zoukankan      html  css  js  c++  java
  • 关于String

    1、String类的修饰符

    这是一个final的类,不可继承,创建的对象不可变

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

    为什么String要设计成不可变的类?

    有以下几个方面可以思考:

    1、为了实现字符串常量池,提高效率

    2、安全,设计为final的,保证在多线程的时候是安全的,可以被多个线程共享

    3、String设计的时候缓存了hash值,不需要重新计算,如果是可变的,每次都需要重新计算

    2、主要成员变量

    private final char value[]; //使用字符数组存放字符串
    private int hash; // Default to 0  缓存哈希值

    3、equals()方法

    重写了Object的equals()方法,判断两个字符串的每一个字符是否相等
    public boolean equals(Object anObject) {
        if (this == anObject) { // 如果两个引用指向的是同一个String对象
            return true;
        }
        if (anObject instanceof String) { // 如果第2个引用指向的对象是String实例
            String anotherString = (String)anObject; // 强制类型转换
            int n = value.length; // 获取第1个引用指向的String对象的字符串长度
            if (n == anotherString.value.length) { // 如果两个字符串长度相等
                // 定义字符数组指针
                char[] v1 = value;
                char[] v2 = anotherString.value;
     
                // 字符依次比较
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

    4、hashCode()方法

    重写了hashCode()方法

    public int hashCode() {
        // 获取字符串缓存散列码
        int h = hash;
        if (h == 0 && value.length > 0) { // 如果字符串缓存散列码为0并且字符串数组长度大于0
            // 定义字符数组指针
            char val[] = value;
     
            // 遍历每个字符
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i]; // 31 * h会被JVM优化成(h << 5) - h
            }
            hash = h; // 修改字符串缓存散列码
        }
        return h;
    }

    5、split()方法

    split()方法的坑比较多,试一下执行
    public static void main(String[] args) {
        String s = "1"; 
        String[] s1 = s.split("-");
        System.out.println(s1.length);-----------------结果是1
    }

    这里建议避开如下坑:

    (1)不要使用如下字符作为分隔符:.$|()[{^?*+\,这些是"Dangling meta character";

    (2)对于空字符串的,也不要使用split,这样分割后的数组长度是1

    (3)注意转义字符

    (4)注意分隔符在最前和最后的情况

    推荐使用的分隔符:单个字符如     "-"  ","   ";"   ":"

    6、native方法 intern()

    调用了intern()方法的字符串对象,将会进入常量池

    /**
         * Returns a canonical representation for the string object.
         * A pool of strings, initially empty, is maintained privately by the class {@code String}.    
         * When the intern method is invoked, if the pool already contains a
         * string equal to this {@code String} object as determined by
         * the method, then the string from the pool is returned. 
       * Otherwise, this {@code String} object is added to the
         * pool and a reference to this {@code String} object is returned.
         * <p>
         * It follows that for any two strings {s} and {t},
         * {s.intern() == t.intern()} is {true}
         * if and only if {s.equals(t)} is {true}.
         * <p>
         * All literal strings and string-valued constant expressions are interned. --------所有字面意义的字符串值和具有字符串值的常量表达式
       * String literals are defined in section 3.10.5 of the
         * <cite>The Java&trade; Language Specification</cite>.
         *
         * @return  a string that has the same contents as this string, but is
         *          guaranteed to be from a pool of unique strings.
         */
    public native String intern();

    7、关"+"操作符

    • String 在执行 + 操作时,编译时期会进行优化。
    • 如果是多个字面量相加,则会在编译时期直接把组合好的字符串放入常量池。
    • 如果有字符串常量参与,以最左边的字符串为参数创建StringBuilder对象,然后依次对右边进行append操作,最后将StringBuilder对象通过toString()方法转换成String对象(注意:中间的多个字符串常量不会自动拼接)

    String s1 = "aa"; // 编译期在常量池中创建 "aa"
    String s2 = "bb"; // 编译期在常量池中创建 "bb"
    String s3 = "aa" + "bb"; // 编译期JVM进行优化,在常量池中创建 "aabb"

    String s4 = s1 + s2 ; // 等价于 String s4 = new StringBuilder().append("aa").append("bb").toString();

    //等价于 String s5 = new StringBuffer("1122").append("aa").append("33").append("44").append("bb").toString();
    String s5 = "11" + "22" + s1 + "33" + "44" + s2;

    8、关于字符串常量池

    (1)双引号字符串:String s1 = "aa";  只在常量池上创建"aa"对象

    (2)new String():  String s2 = new String("aa");  在堆上创建对象"aa",并在常量池上创建常量"aa"

    (3)new String()相加:String s3 = new String("a") + new String("a");

      在堆上创建两个"a",一个"aa"。在常量池中创建了"a"

    (4)String s4 = new String("a") + new String("a");   s4.intern();

      在堆上创建两个"a",一个"aa"。在常量池中创建了"a",并将该对象aa的引用保存到常量池上

     
  • 相关阅读:
    响应式布局,流式布局与固定布局
    垃圾回收机制
    形象讲解时间复杂度
    数据结构和算法简介
    数据结构之栈和队列
    十、str的索引、切片和str常用的操作方法(重点)
    九、基础数类型总览和str、int、bool之间的相互转化
    八、编码的初识和进阶
    七、格式化输出和运算符
    六、while循环
  • 原文地址:https://www.cnblogs.com/yb38156/p/12401816.html
Copyright © 2011-2022 走看看