文章目录
1. 前言
在
C语言
中想要表示字符串只能使用字符数组或者字符指针,但是这种方法已经不符合面相对象的思想,而字符串应用又非常广泛,因此JAVA
提供了String
类。(妈妈再也不用担心我不会用指针了=w=)
- 在JAVA中只要用
""
括起来的字符串就是String
对象
//例如
"hello";
"bite";
//都是String对象
2. 常用方法
2.1 字符串构造
1. 使用常量串构造
String是引用类型
s1是引用变量
"hello"是常量串
s1这个引用,指向了"hello"这个对象,也就是s1存的是这个对象的地址。
public static void main(String[] args){
String s1 = "hello";
}
2. 直接new String
对象
public static void main(String[] args){
String s2 = new String("hello");
}
3. 使用字符数组进行构造
public static void main(String[] args){
char[] arr = {'h','e','l','l','o'};
String s2 = new String(arr);
}
注意:String是引用类型,内部并不存储字符串本身。
在String类的实现源码中,String类的实例变量如下:
- String本身是一个
class类
,类里面有一个value
数组,一个hash
。
- 例子🌰:
在JDK中把用
""
括起来的字符串,表示为常量字符串,这些常量串存储在 方法区的 字符常量池中。
为什么要有字符常量池这个概念呢?
因为在实际开发中,字符串使用的频率很高,为了提高效率,所以把字符串放入字符串常量池中。
public static void main(String[] args) {
// s1和s2引用的是不同对象 s1和s3引用的是同一对象
String s1 = new String("hello");
String s2 = new String("world");
String s3 = s1;
String s4 = "hello";
}
当字符串常量池中没有"hello"这个对象,那么就会往常量池中存入一个"hello"对象,如果下次有引用再指向"hello",程序会自动在常量池中找,是否有这个"hello",如果有就直接指向这个对象,没有则往常量池中存入一个"hello"。
所以上述代码:
执行s1这行代码时,会往常量池中存入一个"hello";
s2这行代码会存入一个"world"。
因此 s1 == s3 == s4。
2.2 String 对象的比较
1. == 比较是否引用同一个对象
注意:对于内置类型,==
比较的是变量中的值;对于引用类型 ==
比较的是引用中的地址。
2. 比较是否相同
boolean equals(Object anObject)方法:按照字典序比较(一个一个往后比较)
Object 是一个大父类,任何类都默认继承Object类。
String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较,
比如:s1.equals(s2)
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("world");
// 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true
// s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出false
System.out.println(s1.equals(s2));// true
System.out.println(s1.equals(s3)); // false
}
String重写equals方法,返回值是
boolean
(不需要自己重写,别人已经重写好了)
public boolean equals(Object anObject) {
// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
if (this == anObject) {
return true;
}
// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
if (anObject instanceof String) {
// 将anObject向下转型为String类型对象
String anotherString =(String)anObject;
int n = value.length;
// 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
if (n ==anotherString.value.length{
char v1[] = value;
char v2[] =anotherString.value;
int i = 0;
// 4. 按照字典序,从前往后逐个字符进行比较
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
3. 比较大小
-
int conpareTo(String s)
方法:按照字典序进行比较。
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。
具体比较方式:
- 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值。
- 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值。
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2));// 不同输出字符差值-1
System.out.println(s1.compareTo(s3));// 相同输出 0
System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}
4. 忽略大小写,比较大小
-
int compareToIgnoreCase(String str)
方法:与compareTo方式相同,但是忽略大小写比较
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("ABC");
String s4 = new String("ABcdef");
System.out.println(s1.compareTo(s2));// 不同输出字符差值-1
System.out.println(s1.compareTo(s3));// 相同输出 0
System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}
2.3 字符串查找
- 常用查找的方法:
方法 | 功能 |
---|---|
char charAt(int index) | 返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常 |
int indexOf (int ch) | 返回ch第一次出现的位置,没有返回-1 |
int indexOf(int ch, int fromIndex) | 从fromIndex位置开始找ch第一次出现的位置,没有返回-1 |
int indexOf(String str) | 返回str第一次出现的位置,没有返回-1 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始找str第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch) | 从后往前找,返回ch第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch, int fromIndex) | 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1 |
int lastIndexOf(String str) | 从后往前找,返回str第一次出现的位置,没有返回-1 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1 |
- 例子🌰:
public static void main(String[] args) {
String s = "aaabbbcccaaabbbccc";
System.out.println(s.charAt(3)); // 'b'
System.out.println(s.indexOf('c')); // 6
System.out.println(s.indexOf('c', 10)); // 15
System.out.println(s.indexOf("bbb")); // 3
System.out.println(s.indexOf("bbb", 10)); // 12
System.out.println(s.lastIndexOf('c')); // 17
System.out.println(s.lastIndexOf('c', 10));//8
System.out.println(s.lastIndexOf("bbb")); //12
System.out.println(s.lastIndexOf("bbb", 10));// 3
}
2.4 字符串替换&拆分
替换方法 | 功能 |
---|---|
String replaceAll(String regex, String replacement) | 替换所有的指定内容 |
String replaceFirst(String regex, String replacement) | 替换收个内容 |
拆分方法 | 功能 |
---|---|
String[] split(String regex) | 将字符串全部拆分 |
String[] split(String regex, int limit) | 将字符串以指定的格式,拆分为limit组 |
- 字符串替换🌰:
注意:由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串。
String str = "hhhhh";
String s1 = str.replaceAll("h","w");
//把所有的'h'替换成'w';
System.out.println(s1); //wwwww
System.out.println(str.replaceAll("h","w"));//wwwww
System.out.println(str); //hhhhh
- 字符串拆分🌰:
String str = "hello hi www";
String[] ans = str.split(" ");//按空格拆分
- 部分拆分🌰:
下述代码只把字符串拆分为2部分
String str = "hello hi www";
String[] ans = str.split(" ",2);//按空格拆分
2.5 转化
1. 数字和字符串转化
public static void main(String[] args) {
// 数字转字符串
String s1 = String.valueOf(1234);
String s2 = String.valueOf(12.34);
String s3 = String.valueOf(true);
String s4 = String.valueOf(new Student("Hanmeimei", 18));
// 注意:Integer、Double等是Java中的包装类型
int data1 = Integer.parseInt("1234");
double data2 = Double.parseDouble("12.34");
2. 大小写转换
注意:由于字符串是不可变对象, 转换不修改当前字符串, 而是产生一个新的字符串。
public static void main(String[] args) {
String s1 = "hello";
String s2 = "HELLO";
// 小写转大写
String s3 = s1.toUpperCase();
System.out.println(s1.toUpperCase());
// 大写转小写
System.out.println(s2.toLowerCase()); }
3. 字符串转数组
String str = "hello";
//1. 直接全部转
char[] arr = str.toCharArray();.
//2.一个一个转
char[] ch = new char[20];
for (int i = 0;i<str.length();i++){
ch[i] = str.charAt(i);
}
4. 格式化
与C语言的printf格式输出一样
2.6 字符串截取
方法 | 功能 |
---|---|
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) | 截取部分内容 |
- 截取🌰:
String str = "helloworld" ;
System.out.println(str.substring(5));
System.out.println(str.substring(0, 5));//从下标0处截取到下标4处
注意事项:
- 索引从0开始。
- 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标。
2.7 其他方法
方法 | 功能 |
---|---|
String trim() | 去掉字符串中的左右空格,保留中间空格 |
String toUpperCase() | 字符串转大写 |
字符串转大写 | 字符串转小写 |
2.8 字符串不可变
以下来自JDK1.8中String类的部分实现:
String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出:
- String类被final修饰,表明该类不能被继承。
- value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
- final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
- 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象。
3. StringBuilder和StringBuffer
Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的。
String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改。
- String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
- String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
- StringBuilder变为String: 调用toString()方法
String+String
会自动拼接为一个StringBuilder对象。
String s = "hello";
s += "world";//拼接自动变为StringBuilder对象,再调用toString(),返回一个新的String 赋值给s;
//这种效率极低
//所以有了StringBuilder
- 常用方法
方法 | 说明 |
---|---|
StringBuff append(String str) | 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、double、float、int、long、Object、String、StringBuff的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) | 扩容 |
void setCharAt(int index,char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str,int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) | 删除index位置字符 |
StringBuffer delete(int start, int end) | 删除[start, end)区间内的字符 |
StringBuffer replace(int start, int end, String str) | 将[start, end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
String substring(int start,int end) | 将[start, end)范围内的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
4. 面试题
- String、StringBuffer、StringBuilder的区别?
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。
- StringBuffer与StringBuilder大部分功能是相似的。
StringBuffer
采用同步处理,属于线程安全操作;而StringBuilder
未采用同步处理,属于线程不安全操作。
- 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】
String str1 = new String("ab"); // 会创建多少个对象
String str2 = new String("a") + new String("b"); // 会创建多少个对象
记得三连喔~ 👍👍🏻👍🏿