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方法是重点。
- ==与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);}
- 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. 常见面试题
- 什么是字符串常量池
字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为 了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中, 就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突 进行共享。 - String是线程安全的吗?
是的,因为String是不可变的,所以是线程安全的。 - 在使用HashMap时,用String做key有什么好处?
HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。 - 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