Java中与字符串相关的常用类有:String StringBuffer StringBuilder等,下面对最常用的String相关用法总结

1. String

1.1 String的特性

  • String类代表字符串。java程序中的所有字符串字面值(如"abc"等)都可以作为此类的实例。
  • String类是一个final类,代表不可变的字符序列。
    字符串是常量,用双引号引起来。它们的值在创建之后不能更改。
  • String对象的字符内容是存储在一个字符数组value[]中的。

1.2 String对象的创建

主要创建方式有两种

  • 直接赋值
String str1 = "hello";
  • 调用String构造方法
String str2 = new String("hello");

直接赋值产生的String对象str1存储在字符串常量池中;new创建的对象str2存储在内存中。

package day22;

public class StringTest {
    public static void main(String[] args) {
        String s = "你好啊";
        System.out.println("通过字面量直接赋值方式创建String对象:" + s);

        s = new String();
        System.out.println("通过调用无参的构造方式创建String对象:" + s);

        s = new String("abc");
        System.out.println("通过调用有参的构造方式创建String对象:" + s);

        char[] chs = {'a','b','c'};

        s = new String(chs);
        System.out.println("通过传入char数组的方式创建String对象:" + s);

        s = new String(chs,0,1);
        System.out.println("通过传入char数组的起始索引和结束索引的方式创建String对象:" + s);


    }
}

1.3 String类的常用方法

  • 返回字符串的长度
public synchronized int length(){}
  • 返回某索引处的字符
public char charAt(int index){}
  • 判断字符串是否为空字符串
public boolean isEmpty() {}
  • 使用默认语言环境,将String中的所有字符转换为小写
public String toLowerCase(){}
  • 使用默认语言环境,将String中的所有字符转换为大写
public String toUpperCase(){}
  • 在忽略大小写的情况下,比较字符串内容是否相同
public boolean equalsIgnoreCase(String anotherString){}
  • 将字符串拼接
public String concat(String str){}
  • 分割字符串
//以逗号分割字符串
public class Test {
    public static void main(String args[]) {
        String str = "小学,初中,高中,大专,本科,研究生,博士";
        String[] buff = str.split(",");
        for(int i=0;i<buff.length;i++){
            System.out.println(buff[i]);
        }
    }
}
//以空格分割字符串
String res = str.split(" ");
//以\\分割字符串(用于IP是否合法的校验中)
String res = str.split("\\");
  • 比较字符串大小(如果小于0,说明当前的字符串比传入的字符串小;如果等于0,那么字符串相等;如果大于0,当前的字符串比插入的字符串大)
public int compareTo(String anotherString){}
  • 从指定索引位置开始截取字符串
public String substring(int beginIndex) {}
  • 将字符串从指定位置截取到结束位置
public String substring(int beginIndex, int endIndex){}
  • 判断当前字符串是否包含指定的char值序列
public boolean contains(CharSequence s){}
  • 返回指定子字符串出现在当前字符串的第一个索引位置
public int indexOf(String str){}
  • 返回指定子字符串在当前字符串中最右边出现的索引位置
public int lastIndexOf(String str){}

1.4 String类型的转换

1.4.1 与基本数据类型的转换

  • 基本数据类型转换为String
public static String valueOf(Object obj){}
  • String转换为基本数据类型
public static int parseXxx(String s) throws NumberFormatException{}
package day22;
public class StringTest {
    public static void main(String[] args) {
        Integer i = 123;
        String s = String.valueOf(i);
        System.out.println("基本数据类型转换为String类型:" + s);
        int parseInt = Integer.parseInt(s);
        System.out.println("String类型转换为基本数据类型:" + parseInt);

    }
}
  • 比较字符串内容是否相同
public boolean equals(Object anObject){}

equals方法是重点。

  1. ==与equals的区别
String str1 = "hello";
String str2 = "hello"
String str3 = new String("hello");
String str4 = new String("hello");
System.out.println(str1 == str2);
System.out.println(str3 == str4);
System.out.println(str3.equals(str4));

输出结果为

true
false
true

原因解释:
== 是用来判断地址是否相同,且直接赋值的字符串对象保存在常量池中,对象str1和str2所指地址相同。由new创建的字符串对象str3和str4保存在堆内存中,地址不同。所以前两个为true false.
String重写后的equals()方法用来判断所指地址对应值是否相同。
3. equals方法继承源
String中对于继承Object类的equals方法进行了重写。
在Object类中,,equals方法的具体实现也是==

public boolean equals(Object obj) {return (this == obj);}
  1. String重写equals方法
public 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类对equals方法进行了重写,所以可以直接用equals方法判断字符串的值是否相等。

  • intern方法
    当嗲用某个字符串对象的intern方法时,会去字符串常量池中寻找,如果已经存在一个值相等的字符串对象的话,直接返回该对象的引用。如果不存在,则在字符串常量池中创建该对象,并返回。zz
在这里插入代码片

1.4.2 与字符数组的转换

  • 字符数组转换为String类型
public String(char value[]){}  //也就是string的一个赋值类型
  • 部分字符数组转换为String类型
public String(char value[], int offset, int count){}
  • String类型转换为字符数组
public char[] toCharArray() {}
package day22;

import java.util.Arrays;
public class StringTest {
    public static void main(String[] args) {
        char[] chs = {'a','b','b'};
        String s = new String(chs);
        System.out.println("字符数组转换为String类型:" + s);
        char[] chars = s.toCharArray();
        System.out.println("String类型转换为字符数组:" + Arrays.asList(chars));
    }
}

2. StringBuffer 与StringBuilder

当对字符串进行修改时,需要用到StringBuffer与StringBuilder类
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

2.1 StringBuffer

2.1.1常用函数

public class Test{
  public static void main(String args[]){
  //初始化一个StringBuffer对象
    StringBuffer sBuffer = new StringBuffer("菜鸟教程官网:");
    StringBuffer res = new StringBuffer("");
    //append将指定的字符串追加到此字符序列
    sBuffer.append("www");
    sBuffer.append(".runoob");
    sBuffer.append(".com");
    System.out.println(sBuffer);  
  }
}
  • 将此字符序列用其反转形式取代。
public StringBuffer reverse()
  • 移除此序列的子字符串中的字符。
public delete(int start, int end)
  • 将字符串插入此序列第i个位置中。
public insert(String str, int i)
  • 使用给定 String 中的字符替换此序列的子字符串中的字符。
replace(int start, int end, String str)
  • 返回此序列中数据的字符串表示形式。
res.toString();
String toString()

2.2 StringBuilder

3. 常见面试题

  1. 什么是字符串常量池
    字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为 了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中, 就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突 进行共享。
  2. String是线程安全的吗?
    是的,因为String是不可变的,所以是线程安全的。
  3. 在使用HashMap时,用String做key有什么好处?
    HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。
  4. String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的?
  • 可变性
    String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
  • 线程安全性
    String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
  • 性能
    每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
  • 对于三者使用的总结
    如果要操作少量的数据用 = String
    单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
    多线程操作字符串缓冲区 下操作大量数据 = StringBuffer