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();

转载于:https://www.cnblogs.com/zongmin/p/11338787.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值