一、String的常用方法
1、字符串构造
public class String_1 {
public static void main(String[] args) {
//1、使用常量串构造
String s1 = "happy";
//2、使用new String对象
String s2 = new String("happy");
//3、使用字符数组构造
char[] cs = {'h','a','p','p','y'};
String s3 = new String(cs);
}
}
1>使用常量串构造
说明:String s1 = “happy”;其中s1表示引用变量,在栈上,happy为字符串常量在常量池
2>new String对象
说明:String s2 = new String(“happy”);其中s2是引用变量,在栈上,s2引用的对象在堆上,这个对象有value值和hash值,value为引用常量"happy"的字符数组
3>字符数组构造
说明:char cs = “happy”;String s3 = new String(cs);
注意:字符串的存储
2、String对象的比较
2.1、== 比较是否引用同一个对象
说明:相当于比较是否为同一个地址
public class String_1 {
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = s1;
System.out.println("s1==s2?"+(s1==s2));
System.out.println("s1==s3?"+(s1==s3));
}
}
//结果:
s1和s2引用同一个对象?false
s1和s3引用同一个对象?true
2.2、boolean equals()方法比较是否相等
说明:String类重写了其父类Object的equals方法,使其功能变为比较字符串是否相等,而不是比较地址。
public class String_1 {
public static void main(String[] args) {
String s1 = new String("world");
String s2 = new String("world");
String s3 = s1;
System.out.println("s1等于s2?"+s1.equals(s2));
System.out.println("s1等于s3?"+s1.equals(s3));
}
}
//结果:
s1等于s2?true
s1等于s3?true
2.3、int compareTo()比较大小
说明:String类实现了comparable接口,重写了compareTo方法
public class String_1 {
public static void main(String[] args) {
String s1 = new String("world");
String s2 = new String("apple");
if(s1.compareTo(s2)>0) {
System.out.println("s1>s2");
}else if(s1.compareTo(s2)<0){
System.out.println("s1<s2");
}else{
System.out.println("s1==s2");
}
}
}
//结果:
s1>s2
2.4、IgnoreCase()忽略大小写比较
说明:boolean equalsIgnoreCase()和int compareIgnoreCase()都是String类自己的方法。
1、 s1.equalsIgnoreCase(s2)=>忽略大小写比较s1,s2是否相等
2、s1.compareToIgnoreCase(s2)=>忽略大小写比较s1,s2大小
public class String_1 {
public static void main(String[] args) {
String s1 = new String("apple");
String s2 = new String("Apple");
//1、equalsIgnoreCase
System.out.println("equalsIgnoreCase::s1==s2?"+s1.equalsIgnoreCase(s2));
System.out.println("==========");
//2、compareIgnoreCase
if(s1.compareToIgnoreCase(s2)>0) {
System.out.println("compareToIgnoreCase::s1>s2");
}else if(s1.compareToIgnoreCase(s2)<0){
System.out.println("compareToIgnoreCase::s1<s2");
}else{
System.out.println("compareToIgnoreCase::s1==s2");
}
}
}
//结果:
equalsIgnoreCase::s1==s2?true
==========
compareToIgnoreCase::s1==s2
3、字符串查找
3.1、查找字符串里字符位置
说明:
1、char charAt(int index)//查找目标下标的字符,除它之外都是查字符的下标
2、int indexOf(int ch)
3、int indexOf(char ch, int fromIndex)
4、int lastIndexOf(int ch)
5、int lastIndexOf(int ch, int fromIndex)
public class String_1 {
public static void main(String[] args) {
String s = "aabbbcccbbb";
//1、char charAt(int index)//查找目标下标的字符,除它之外都是查下标
System.out.println(s.charAt(2));//b
//2、int indexOf(int ch) //将字符转换为ASCII码再运算
System.out.println(s.indexOf('b'));//2
//3、int indexOf(char ch, int fromIndex) //从fromIndex下标开始从前往后找
System.out.println(s.indexOf('b', 5));//8
//4、int lastIndexOf(int ch)
System.out.println(s.lastIndexOf('c'));//7
//5、int lastIndexOf(int ch, int fromIndex)//从fromIndex下标开始从后往前找
System.out.println(s.lastIndexOf('b', 7));//4
}
}
//结果
b
2
8
7
4
3.2、查找子串位置
说明:
1、int indexOf(String str)
2、int indexOf(String str, fromIndex)
3、int lastIndexOf(String str)
4、int lastIndexOf(String str, formIndex)
public class String_1 {
public static void main(String[] args) {
String s = "aabbcccbbb";
//1、int indexOf(String str)
System.out.println(s.indexOf("bb"));//2
//2、int indexOf(String str, fromIndex)
System.out.println(s.indexOf("bb", 4));//7
//3、int lastIndexOf(String str)
System.out.println(s.lastIndexOf("cc"));//5
//4、int lastIndexOf(String str, formIndex)
// 从fromIndex从后往前向前找,
// 第一个字母符合后向后接着比较剩下的字母,若剩下的也相等,则返回子串第一个字母在母串中的下标,
// 否则继续查找,如果遍历完都没有就返回-1
System.out.println(s.lastIndexOf("bb", 3));//2
}
}
//结果:
2
7
5
2
4、转化
4.1、数值和字符串转化
说明:
其它=》字符串:String.valueOf(),valueOf()是String类的静态方法,所以用类名访问
字符串=》其它:其它类型.parse…()
public class String_1 {
public static void main(String[] args) {
//1、数字转换为字符串
String s1 = String.valueOf(1234);
String s2 = String.valueOf(12.34);
String s3 = String.valueOf(true);
//这个相当于toString
String s4 = String.valueOf(new Student("Hanmeimei", 18));
System.out.println(s1+"\n"+s2+"\n"+s3+"\n"+s4);
System.out.println("===================");
//2、字符串转换为数字
int a = Integer.parseInt(s1);
double d = Double.parseDouble(s2);
boolean b = Boolean.parseBoolean(s3);
System.out.println(a+"\n"+d+"\n"+b);
//Student类型转换为字符串后,不能再次转换为Student类型。
}
}
class Student {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//结果:
1234
12.34
true
Student{name='Hanmeimei', age=18}
===================
1234
12.34
true
4.2、大小写转换
说明:
小=》大:字符串.toUpperCase()
大=》小:字符串.toLowerCase()
public class String_1 {
public static void main(String[] args) {
String s1 = "help";
String s2 = "HELLO";
System.out.println(s1.toUpperCase());
System.out.println(s2.toLowerCase());
}
}
4.3、字符串和数组互相转换
1、字符串=》数组:字符串.toCharArray()
2、数组=》字符串:String 名 = new String(数组名)
public class String_1 {
public static void main(String[] args) {
String s = "hello";
char[] chars = s.toCharArray();
//1、字符串=》数组
for (int i=0;i<s.length();i++){ //s是字符串length后面加(),而chars是数组,求长度不加括号
System.out.print(chars[i]);
}
System.out.println("\n=============");
//2、数组=》字符串
String s1 = new String(chars);
System.out.println(s1);
}
}
//结果:
hello
=============
hello
4.4、format格式化
String s = String.format(“%d-%d-%d”,2022,9,9)
public class String_1 {
public static void main(String[] args) {
String s = String.format("%d-%d-%d",2022,9,9);
System.out.println(s);
}
}
//结果
2022-9-9
5、字符串替换
说明:
1、字符串.replaceAll()
2、字符串.replaceFirst()
public class String_1 {
public static void main(String[] args) {
String s = "HelloWorld";
String s1 = s.replaceAll("l","x");
System.out.println(s1);
String s3 = s.replaceFirst("l","x");
System.out.println(s3);
}
}
//结果:
HexxoWorxd
HexloWorld
6、字符串拆分
6.1、简单的split分割
1、String[] strings = 字符串.split(“分割符”)
2、String[] strings = 字符串.split(“分割符, 分成字符串成员个数”)
public class String_1 {
public static void main(String[] args) {
String s1 = "My name is LiHua";
//1、String[] strings = 字符串.split("分隔符")
String[] strings = s1.split(" ");
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i]);
}
System.out.println("===================");
//2、String[] strings = 字符串.split("分隔符, 分成字符串成员个数")
String[] strings1 = s1.split(" ",3);
for (int i = 0; i < strings1.length; i++) {
System.out.println(strings1[i]);
}
}
}
//结果:
My
name
is
LiHua
===================
My
name
is LiHua
6.2、转义分割和多重分割
说明:
1、用 "\分隔符"分割".“,”+“,”*“,”|"等符号
2、用 “\\“分割”\”
3、多重分割用 “分隔符 | 分隔符”
public class String_1 {
public static void main(String[] args) {
//1、用"\\符号"分割 ".","+","*","|"等符号
String s1 = "192.169.1.1";
String[] strings1 = s1.split("\\.");
for (int i = 0; i < strings1.length; i++) {
System.out.println(strings1[i]);
}
System.out.println("===================");
//2、"\\\\"分割"\\"
String s2 = "abc\\bde|hf+mb"; //第一个\转义第二个\使第二个成为字符
String[] strings2 = s2.split("\\\\");
for (int i = 0; i < strings2.length; i++) {
System.out.println(strings2[i]);
}
System.out.println("===================");
//3、多重分割用"|"
String s3 = "zhang=San&wang=wu";
String[] strings3 = s3.split("=|&");
for (int i = 0; i < strings3.length; i++) {
System.out.println(strings3[i]);
}
}
}
//结果:
192
169
1
1
===================
abc
bde|hf+mb
===================
zhang
San
wang
wu
7、字符串截取
说明:
1、字符串.subString(int beginIndex)
2、字符串.subString(int beginIndex, int endIndex),其中截取片段不包括endIndex,遵循左闭右开
public class String_1 {
public static void main(String[] args) {
//1、字符串.subString(int beginIndex)
String s1 = "hello world";
String cs1 = s1.substring(1);
System.out.println(cs1);
//2、字符串.subString(int beginIndex, int endIndex)
//其中截取片段不包括endIndex,遵循左闭右开
String cs2 = s1.substring(1,4);
System.out.println(cs2);
}
}
//结果
ello world
ell
8、其它操作方法
8.1、求字符串长度length()
说明:
求字符串长度: 字符串.length()
求数组长度:==数组名.length ==
8.2、trim()省略空格
说明:
trim()会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等)
二、字符串常量池
1、常量池介绍
说明:
1、在Java程序中,类似于1,2,3.14,“hello”,等字面类型常量经常使用,为了使程序运行更快,更节省内存,Java为8种数据类型和String类都提供了常量池。
2、为了运行效率和节省空间,java中还引入了:
- .Class文件常量池:每个.Java源文件编译后生成.Class文件中会保存当前类中的字面常量以及符号信息
- 运行时常量池:在.Class文件被加载时,.Class文件中的常量池被加载到内存中称为运行时常量池。
2、String对象内存深究
2.1、直接使用字符串常量进行赋值
一、例子:
String s1 = “hello”;
String s2 = “hello”;
二、内存:
三、注意:
- 在字节码文件加载时,"hello"常量串已经创建好了,并保存在字符串常量池中
- 当使用String s1 = “hello”;创建对象时,先在字符串常量池中查找该常量串,找到后,就将字符串(对象)引用赋值给s1。
2.2、new创建String类对象
一、例子:
String s1 = new String(“hello”);
String s2 = newString(“hello”);
二、内存:
第1步:执行第一句前,先检查字符串常量池没有"hello",所以先创建对象
第2步:执行String s1 = new String(“hello”)。先检查在常量池中已经存储"hello"字符串,找到后把这个字符串存放的value里的数组"hello"的地址传给new String的value。String s2 = new String(“hello”)操作一样。
三、在IDEA中证明:
注意:所有对象指向同一个数组
2.3、intern方法
说明:intern()是一个native方法(底层用C/C++实现,看不到源代码)
作用:手动将创建的String对象添加到字符串常量池中。
解释:
如上面代码,调用s1.intern()后,s1就在字符串常量池。s2就直接找到s1创建好的数组,从而提高效率和节省空间。
3、面试题
请解释String类中两种对象实例化的区别
一、String str = “hello”;
解释:
只开辟一块堆内存空间(有2个对象,1个数组和1个字符串对象),保存在字符串常量池中,然后str共享常量池中的String对象
二、String str = new String(“hello”);
解释:
开辟两块堆内存空间(3个对象,1个数组对象,2个字符串对象),字符串"hello"保存在字符串常量池中,然后用常量池中的String对象给新开辟的String对象赋值
三、String str = new String(new char[]{‘h’,‘e’,‘l’,‘l’,‘o’})
解释:
一、先在堆上创建一个String对象(3个对象,2个数组对象,1个字符串对象),二、然后重新开辟并创建”hello“的字符串,三、再利用copyOf重新开辟数组空间并拷贝,四、最后将new的参数字符串数组的地址拷贝到String对象value中
三、字符串的不可变性
1、字符串的不可变性
1、不可变性
1>String类下修饰它的final表示:String类不能被继承。
2>private final char value[]中的final表示:自身的值不能改变(与C语言中的const相似)即不能引用其他数组,但是引用空间中的内容可以修改。private是限制了它不能改变的根本原因
2、修改字符串
注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新的对象,效率非常低下
如下代码:
public class String_2 {
public static void main(String[] args) {
String s = "hello";
s += " world";
System.out.println(s); // 输出:hello world
}
}
2、StringBuilder和StringBuffer修改字符串
说明:
StringBuilder和StringBuffer都是对原来的字符串进行操作
2.1、append方法:
public class String_2 {
public static void main(String[] args) {
StringBuilder s1 = new StringBuilder("hello");
s1.append(" world");
System.out.println(s1);
}
}
//结果:
hello world
2.2、reverse方法:
public class String_2 {
public static void main(String[] args) {
StringBuilder s1 = new StringBuilder("hello");
System.out.println(s1);
StringBuilder s2 = s1.reverse();
System.out.println(s2);
}
}
//结果:
hello
olleh
2.3、可变字符串IDEA证明
public class String_2 {
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = sb1;
sb1.append(" world"); // hello world
System.out.println(sb1==sb2);
}
}
//结果:
true
3、可变字符串和不可变字符串之间的转换
说明:
1、String=》StringBuilder:利用StringBuilder构造方法或append()方法
2、StringBuilder=》String:调用toString()方法
public class String_2 {
public static void main(String[] args) {
//1、String=》StringBuilder
StringBuilder s1 = new StringBuilder("hello");
s1.append(" world");
//2、StringBuilder=》String
String s2 = s1.toString();
System.out.println(s1);
}
}
4、面试题
题一、String、StringBuilder、Stringbuffer的区别
- 1、String的内容不能修改,StringBuffer和StringBuilder的内容可以修改
- 2、StringBuffer和StringBuilder的大部分功能是相似的
- 3、StringBuffer是多线程操作,采用同步处理,属于线程安全操作,StringBuilder未采用同步处理,属于线程不安全操作
题二、以下各创建了多少个字符串对象
1、String str = new String(“ab”);
2、String str = new String(“a”) + new String(“b”);
- 1、两个对象,一个是常量池中共用字符串,一个是new的字符串
- 2、六个对象,两个常量池共用字符串,两个new的字符串,一个"a"+"b"的字符串,一个返回new “a”+"b"的字符串。
最后,祝大家中秋快乐!