• String字符串


    String不可变性

    • JDK 1.8 中,String 使用 char 数组存储数据
    public final class String 
    	implements java.io.Serializable, Comparable<String>, CharSequence {
        private final char[] value;
    }
    
    • JDK 1.9 中,String 类改用 byte 数组存储字符串,同时用 coder 来标识使用哪种编码
    public final class String 
    	implements java.io.Serializable, Comparable<String>, CharSequence {
        private final byte[] value;
        private final byte coder;
    }
    

    String 是一个 final 类,意味着它不可以被继承,并且存储数据的 value 数组也被声明为 final,意味着 value 数组初始化后不能再引用其他数组,再加上 String 内部没有更改 value 数组数据的方法,所以 String 不可变。

    public static void main(String[] args) {
        String s1 = "abc";
        //不可变,意味着s1数据不能更改,所以下列过程是重新创建一个新对象赋给s1
        s1 = "def";
    }
    

    String Pool

    常量池的介绍参考此文:https://www.cnblogs.com/jinggod/p/8425748.html

    字符串常量池(String Pool)保存着所有字符串字面量。当程序第一次使用某个字符串字面量时,会使用常量池缓存该字面量,后续程序需要再次使用该字面量时,会直接从常量池中取。

    public static void main(String[] args) {
        //第一次使用字符串字面量,会在常量池创建一个字符串对象,s1指向该对象
        String s1 = "Love You";
        //s2的结果在编译期间就已经计算出来,是字符串字面量,从常量池中取数据,s2指向常量池中的字符串对象
        String s2 = "Love" + " You";
        //s3结果在编译期无法计算出,运行时才能计算,所以需要在堆中创建对象
        String s3 = s2 + "";
        //使用new直接在堆中创建对象
        String s4 = new String("Love You");
    
        System.out.println(s1 == s2); //true
        System.out.println(s1 == s3); //false
        System.out.println(s1 == s4); //false
    }
    

    在运行过程,可以使用 String 的 intern() 方法将字符串添加到 String Pool 中。当一个字符串调用 intern() 方法时,如果 String Pool 已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定,那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。

    public static void main(String[] args) {
        String s1 = new String("aaa");
        String s2 = new String("aaa");
        System.out.println(s1 == s2);     //false
        
        String s3 = s1.intern();          //常量池中无数据,添加
        String s4 = s2.intern();          //常量池中有数据,从常量池中取
        System.out.println(s3 == s4);     //true
    }
    

    JDK 1.7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 JDK 1.7 之后,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。

    new String("abc") 解析

    使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有 "abc" 字符串对象)。

    • "abc" 属于字符串字面量,因此编译时期会在 String Pool 中创建一个字符串对象,存储该字符串字面量;
    • 运行期时,使用 new 的方式会在堆中创建一个字符串对象。

    String类方法

    构造方法

    //构造一个空字符串对象
    String();  
    
    //通过byte数组构造字符串对象
    String(byte[] bytes);    
    
    //指定字符集解析byte数组
    String(byte[] bytes, Charset charset);  
    
    //通过byte数组,从offset开始,总共length长的字节构造字符串对象
    String(byte[] bytes,int offset,int length);  
    
    //指定字符集
    String(byte[] bytes,int offset,int length, Charset charset);  
    
    //通过char数组构造字符串对象
    String(char[] value); 
    
    //通过char数组,从offset开始,总共length长的字节构造字符串对象
    String(char[] char,int offset,int length);
    
    //构造一个original的副本,拷贝一个original
    String(String original); 
    
    //通过StringBuffer对象构造字符串对象
    String(StringBuffer buffer);
    
    //通过StringBuilder对象构造字符串对象
    String(StringBuilder builder);
    

    获取序列长度 length

    //返回当前字符串长度
    int length();
    

    获取指定字符 charAt

    //返回字符串指定位置的字符,index取值0到length()-1
    char charAt(int index);
    

    获取数组对象 getBytes/toCharArray

    //将String对象转换成byte数组
    byte[] getBytes();
    
    //指定字符集
    byte[] getBytes(String charsetName)
    
    //将该String对象转换成char数组
    char[] toCharArray();
    

    比较字符串 compareTo/compareToIgnoreCase

    //比较字符串大小,相等返回0;不相等时,返回第一个不相等字符的字典序差;
    //如果有个字符串为另一个字符串前缀,则返回长度差,即this.length()-anotherString.length()
    int compareTo(String anotherString);
    
    //不考虑大小写
    int compareToIgnoreCase(String anotherString);
    

    比较字符串 equals/equalsIgnoreCase/contentEquals

    //String类重写了equal方法。字符串与指定对象的字符序列相等返回true,不等返回false
    boolean equals(Object anObject);  
    
    //不区分大小写比较
    boolean equalsIgnoreCase(Object anObject);
    
    //内部实现:
    boolean equals(Object anObject){
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = value.length;
            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;
    }
    
    //将 String 与 StringBuilder 的字符序列进行比较,相等返回 true,不能返回 false
    boolean contentEquals(StringBuffer sb);
    //内部实现:
    public boolean contentEquals(StringBuffer sb) {
        synchronized (sb) {
            return contentEquals((CharSequence) sb);
        }
    }
    

    此处顺便一提,= 运算符比较的是是否为同一个字符串对象的引用,而不是比较字符序列,所以比较字符序列使用 equals 方法。

    连接字符串 concat/"+"

    //与运算符“+”号功能相同
    String concat(String str);
    

    截取字符串 substring

    //获取从 beginIndex 位置开始到结束的子字符串
    String substring(int beginIndex);
    
    //获取从 beginIndex 位置开始到 endIndex 位置(不包括)的子字符串
    String substring(int beginIndex, int endIndex);
    

    去掉首尾空字符 trim

    //去掉该字符串首尾空字符
    String trim();
    

    字符串拆分 split

    //regex -- 正则表达式分隔符
    //limit -- 分割的份数
    String[] split(String regex);
    String[] split(String regex, int limit);
    
    String str = new String("Welcome-to-Blog");
    
    for (String retval: str.split("-")){
    	System.out.println(retval);  
    }
    //输出
    Welcome
    to
    Blog
    
    for (String retval: str.split("-", 2)){
         System.out.println(retval);
    }
    //输出
    Welcome
    to-Blog
    

    大小写 toLowerCase/toUpperCase

    //将字符串转换成小写
    String toLowerCase();
    
    //将字符串转换成大写
    String toUpperCase();
    

    替换 replace/replaceAll/replaceFirst

    //用newChar字符替换字符串中出现的所有oldChar字符,并返回替换后的新字符串
    String replace(char oldChar, char newChar);
    
    //用字符序列replacement替换所有出现的target,内部实现机理是replaceAll。
    String replace(CharSequence target, CharSequence replacement);
    
    //使用给定的参数replacement替换字符串中所有匹配给定的正则表达式的子字符串。
    String replaceAll(String regex, String replacement);
    
    //使用给定的参数replacement替换字符串中第一个匹配给定的正则表达式的子字符串
    String replaceFirst(String regex, String replacement);
    

    前/后缀匹配 startsWith/endsWith

    //用于检测字符串是否以指定的前缀开始
    boolean startsWith(String prefix);
    
    //toffset--字符串中开始查找的位置。
    boolean startsWith(String prefix, int toffset);
    
    //用于检测字符串是否以指定的后缀结束
    boolean endsWith(String suffix);
    

    定位 indexOf/lastIndexOf/contains

    //返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
    int indexOf(int ch);
    
    //返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引
    int indexOf(int ch, int fromIndex);
    
    //返回指定字符序列在字符串中第一次出现处的索引
    int indexOf(String str);
    
    //返回从 fromIndex 位置开始查找指定字符序列在字符串中第一次出现处的索引
    int indexOf(String str, int fromIndex);
    
    //同理,LastIndexOf 具有同样的方法,只是返回的是最后一次出现处的索引
    
    //是否包含子字符串
    boolean contains(CharSequence s);
    

    StringBuffer和StringBuilder及其方法

    String、StringBuffer、StringBuilder都为字符串类,三者都实现了 CharSequence 接口,可认为 CharSequence 是一个字符串的协议接口。

    三者的区别:

    • String 是不可变类,而 StringBuffer 和 StringBuilder 是可变的。
    • String 是不可变类,所有线程安全;StringBuffer 是线程安全的,内部使用 synchronized 进行同步;而 StringBuilder 不是线程安全的。

    通常情况下,如果需创建序列可变的字符串对象,优先考虑 StringBuilder 类,因为线程无需同步,性能高。

    StringBuffer 和 StringBuilder 方法大多与 String 差不多,但是由于他们是可变的,所以可以进行增、删、改等操作,下面以 StringBuffer 为例的一些方法。

    追加字符串 append

    //将指定的数据追加到此字符序列后,有多种数据类型的重载方式,这里仅列四种
    StringBuffer append(String str);
    StringBuffer append(char[] str);
    StringBuffer append(char[] str, int offset, int len);
    StringBuffer append(char c);
    

    删除指定字符序列 delete

    //移除此序列的子字符串中的字符(包括 start, 不包括 end)
    delete(int start, int end);
    

    删除指定字符 deleteCharAt

    //删除指定字符
    StringBuffer deleteCharAt(int index);
    

    替换字符串序列 replace

    //使用给定的Str替换此序列的子字符串中的字符(包括 start,不包括 end)
    StringBuffer replace(int start, int end, String str);
    

    插入字符序列 insert

    //在offset位置插入指定的数据,有多种数据类型的重载方式,这里仅列四种
    StringBuffer insert(int offset, String str);
    StringBuffer insert(int offset, char[] str);
    StringBuffer insert(int offset, char[] str, int offset, int len);
    StringBuffer insert(int offset, char c);
    

    设置指定字符 setCharAt

    //将index位置的字符设置为ch
    void setCharAt(int index, char ch);
    

    反转字符串 reverse

    //将此字符序列用其反转形式取代
    StringBuffer reverse();
    
  • 相关阅读:
    flask 源码专题(七):threading.local和高级
    flask 源码专题(六):session处理机制
    flask 源码专题(五):SqlAlchemy 中操作数据库时session和scoped_session的区别
    flask 源码专题(四):wtforms Form实例化流程以及csrf验证
    flask 源码专题(三):请求上下文和应用上下文入栈与出栈
    python 追踪函数调用
    flask 源码专题(一):app.run()的背后
    flask 源码专题(二):请求上下文与全文上下文
    边框间距 | border-spacing (Miscellaneous Level 2)
    边框样式属性 | border-top-style (Backgrounds & Borders)
  • 原文地址:https://www.cnblogs.com/zongmin/p/11338787.html
Copyright © 2020-2023  润新知