写笔记记录自己的学习记录以及巩固细节
目录
1.String类的常用方法
1.1 字符串构造
//两种方法一样,常用第一种
String str1 = "hello";//直接指向常量池,常量池中的哈希值指向"hello"数组
String str2 = new String("abc");//凡是new的都是在堆上开辟空间,堆上的空间再指向String的地址
//字符数组
char[] chars = {'a', 'v', 's', 'd'};
String str3 = new String(chars);
System.out.println(str3);
str1 是在常量池中创建一个新的String对象
只要是引号引出来的值都会存放在常量池中
str2 是使用了new方法在堆上开辟了一个String大小的空间
chars 是一个字符数组,直接在堆上开辟空间
str3 在堆上new了一个String对象
所有String对象中都有一个value和hash,其中value指向一个字符数组
1.2 String对象的比较
1.2.1 比较两个字符串是否相等
s1.equals(s2)方法 判断s1,s2两字符串的值是否相等,返回boolean值
s1.equalsIgnoreCase(s2) 忽略字母的大小写进行比较,返回boolean值
使用注意事项:最好把要比较的字符串放前面,可以避免空指针的风险
String string1 = new String("aaaaa");
//string1 = null;
//若使用空指针则不能 '.',会报错
System.out.println(string1.equals("aaaaa"));//若string1为null,则系统报错
//而使用"aaaaa"在前可以避免空指针异常的风险
System.out.println("aaaaa".equals(string1));
"=="比较的是两个字符串的地址是否相同
"equals"比较的是连个字符串的值是否相等
//利用new出来的字符串才算开辟新的空间
//但只要出现引号引起来的数据就会存放在在常量池中
String string1 = new String("aaaaa");
String string2 = new String("aaaaa");
//两个哈希地址一样,即都指向常量池同一个位置
System.out.println(string1.hashCode());//92567585
System.out.println(string2.hashCode());//92567585
//但 == 的结果为false,即在堆上的地址不同
System.out.println(string1 == string2);//false == 比较的是两个变量的地址是否相等
System.out.println(string1.equals(string2));//true equals比较的是具体值是否相等
有图可知,String虽然创建出了两个相同的值,但是在堆上开辟了两个不同地址的String对象,但两个String对象中的value指向的常量字符数组是同一个。
1.2.2 比较两个字符串的大小
s1.compareTo(s2) 比较s1,s2的大小,若s1 > s2返回正值,反之返回负值,若相等返回0
s1.compareToIgnoreCase(s2) 忽略大小写进行比较,返回值和compareTo()一样
//比较字符串的大小
public static void test2() {
String s1 = new String("hello");
String s2 = new String("Hello");
int ret = s1.compareTo(s2);
//忽略大小写进行比较
ret = s1.compareToIgnoreCase(s2);
if (ret > 0) {
System.out.println("s1 > s2");
} else if (ret < 0) {
System.out.println("s1 < s2");
} else {
System.out.println("s1 == s2");
}
}
1.3 字符串查找
s1.charAt(i) 返回s1中下标为i的字符
s1.indexOf('ch') 从字符串第一个字符查找,返回第一次出现’ch'字符的下标,停止查找
s1.indexOf('ch',i) 从下标为i的位置开始往后查找,返回第一次出现’ch'字符的下标
s1.indexOf("String" )从头开始查找,返回第一次出现"String"的第一个字符的下标
s1.indexOf("String",i) 同上
s1.lastIndexOf( ) 从尾部开始往前查找,用法和前面一样
//字符串中查找字符
public static void test3() {
String s1 = new String("haekasdj");
for (int i = 0; i < s1.length(); i++) {
//charAt(i) 拿到某个位置的字符
char ch = s1.charAt(i);
System.out.println(ch);
}
//indexOf(),查找,若找到返回下标,找不到返回-1
//indexOf('char') 从头开始找,遇到第一个查找的字符就结束, 返回找到字符的下标
System.out.println(s1.indexOf('a'));
//indexOf('char',i)从i下标开始找,找到第一个查找的字符就停止 ,返回该下标
System.out.println(s1.indexOf('a', 3));
//indexOf("String")从头开始找,找到第一个字符串第一个字符的下标
System.out.println(s1.indexOf("abc"));// -1
System.out.println(s1.indexOf("aek"));// 1
//从下标3开始找,返回第一个找到的字符串第一个字符的下标
System.out.println(s1.indexOf("asd",3));
//lastIndexOf()从后往前找,和以上用法相同
System.out.println(s1.lastIndexOf('a'));
}
1.4 字符串的转化
1.4.1 字符串转整数
String.valueOf()
参数转字符串
s1 = String.valueOf()
参数可以是int,char,long,float,boolean,double一类的数字
也可以是类Object
字符串 char[]
//valueOf 把参数转化为字符串
String s1 = String.valueOf(1234);
System.out.println(s1);
String s2 = String.valueOf("alskdjlkajsd");
System.out.println(s2);
//转换类时,该类中必须重写ToString方法
String s3 = String.valueOf(new Student("xiaoli", 12));
System.out.println(s3);
输出
1234
alskdjlkajsd
Student{name='xiaolei', age=12}
1.4.2 字符串转数字
Interger.parseInt()
Double.parseDouble()
//parseInt/parseDouble 字符串 转 整数
int a1 = Integer.parseInt("123123123");
System.out.println(a1);
double a3 = Double.parseDouble("12309.1203");
System.out.println(a3);
1.4.3 大小写的转换
toUpperCase() //字符串中字母全部转大写
toLowerCase() //字符串中字母全部转小写
//toUpperCase() 小写转大写 汉字不变
String s1 = "hellGtasT高";
String ret = s1.toUpperCase();
System.out.println(ret);
//toLowerCase() 大写转小写 汉字不变
ret = s1.toLowerCase();
System.out.println(ret);
输出
HELLGTAST高
hellgtast高
1.4.4 字符串与数组之间转换
toCharArray()
没有toIntArray(),因此不能用整数数组接收
String s1 = "asdasd";
//字符串转数组
char[] ch = s1.toCharArray();
System.out.println(Arrays.toString(ch));
//数组转字符串
String s2 = new String(ch);
System.out.println(s2);
//不能将字符串转换成整数数组
//int[] arr = "123123".toCharArray();
1.4.5 格式化输出
String.format() 可以像C语言那样控制格式输出
//格式化输出 String.format()
public static void test1() {
String s1 = String.format("%d,%d,%d", 2024, 4, 21);
System.out.println(s1);//2024,4,21
}
1.5 字符串的替换
s1.replace('oldChar', 'newChar') 将字符串的某个字符替换为新字符,返回一个新的字符串
s1.replace("String", "String") 将某个字符串替换为新的字符串,返回一个新的字符串
s1.replaceFirsrt() 将第一个old字符或字符串替换为新的
//将字符串中的某个字符替换,返回一个新的字符串
String s1 = "asdasdasd";
String ret = s1.replace('a', 'd');
System.out.println(ret);//dsddsddsd
//也可以将某段字符替换为任意字符串
String s2 = "asdasdasdasd";
String ret2 = s2.replace("asd", "qweqwe");
System.out.println(ret2);//qweqweqweqweqweqweqweqwe
//替换第一个字符串 或字符
String s3 = "asdasdasd";
String ret3 = s3.replaceFirst("asd", "asdfgdfgfgh");
System.out.println(ret3);//asdfgdfgfghasdasd
1.6 字符串的拆分
s1.split(char) 以某个字符为分割符,返回一个字符串数组
s1.split(char,int) 以某个字符串为分割符,限制分割为几个字符串,但不会平均分
//字符串拆分 split
public static void test3() {
//是该字符串根据某个字符分割开,返回一个字符串数组
String s1 = "zhangsan wangwu 爱上了的骄傲 zhao2";
String arr[] = s1.split(" ");
System.out.println(arr.length);
System.out.println(Arrays.toString(arr));
//[zhangsan, wangwu, 爱上了的骄傲, zhao2]
//多加一个limit参数,即控制分组的数量(但不会平分,会找打第一个分隔符进行分割)
String arr_[] = s1.split(" ", 2);
System.out.println(Arrays.toString(arr_));
//[zhangsan, wangwu 爱上了的骄傲 zhao2]
// '.' 和 '\'很特殊,需要\\进行转义
String s2 = "2024.4.21";
String arr2[] = s2.split("\\.");
System.out.println(Arrays.toString(arr2));//[2024, 4, 21]
String s3 = "2024\\4\\21";
System.out.println(s3);//2024\4\21
String arr3[] = s3.split("\\\\");//表示分隔符为"\\"
System.out.println(Arrays.toString(arr3));//[2024, 4, 21]
//多个分割符,用|来分割分隔符
String s4 = "asd&gaf fdgg.asddsasd";
String arr4[] = s4.split("&| |\\.");//表示三个分隔符 & 和 ' ' 和 '.'
System.out.println(Arrays.toString(arr4));//[asd, gaf, fdgg, asddsasd]
}
1.7 字符串的截取
s1.substring(int) 从下标int作为新字符串的头,从该下标开始到尾部截取原s1,返回新字符串
s1.substring(int m,int n) 截取s1的下标[m,n),返回新字符串
//截取字符串 substring(int)
public static void test4() {
String s1 = "asddfgghjghj";
//从某个下标开始往后作为一个新字符串的第一个字符[2,tail]
String ret1 = s1.substring(2);
System.out.println(ret1);//ddfgghjghj
String ret2 = s1.substring(2, 5);//[2,5),即下标为2,3,4的字符作为新字符串
System.out.println(ret2);//ddf
}
1.8 其他操作方法
1.8.1 trim()
s1.trim() 除去s1两端的空格
//除去字符串左右两边的空格trim()
public static void test5() {
String s1 = " asdjlkw asd ";
System.out.print(s1);
System.out.println("ppppppppppppppppppp");
String s2 = " asdwasd fgdh ";
String ret2 = s2.trim();
System.out.print(ret2);
System.out.println("pppppppppppppppppp");
}
输出
asdjlkw asd ppppppppppppppppppp
asdwasd fgdhpppppppppppppppppp
1.8.2 contains()
s1.contains("String") 判断s1中是否有String片段 ,返回boolean值
//判断字符串中是否包含 某一段字符串contains,返回类型为boolean
public static void test6() {
String s1 = " hello asdkhello";
System.out.println(s1.contains("hello"));//true
}
1.8.3 endWith(),startsWith()
s1.endWith("String") 判断s1是否以String结尾
s1.startsWith("String") 判断s1是否以String开头 返回boolean值
//判断字符串是否是以某段字符串结尾 或开头的 返回boolean
public static void test7() {
String s1 = "asd sdfjlf kkk";
System.out.println(s1.endsWith("kkk"));//true
System.out.println(s1.startsWith("asd"));//true
}
1.9 字符串常量池
凡是出现在双引号中的值,都会被保存在字符串常量池中。
凡是使用new关键字开辟的新空间都是在堆上。
如果没使用new开辟空间,那么对于常量池所存在的数据,有且只能有一个,也就是多个变量可以指向同一个空间
双引号中的数据 系统会先检查常量池中是否有该数据 如果有就直接引用 如果没有就会把该常量放进去 即在常量池中只会维护一个“abcd"对象
public static void test1() {
//双引号中的数据 系统会先检查常量池中是否有该数据
//如果有就直接引用 如果没有就会把该常量放进去
//即在常量池中只会维护一个“aaaaa"对象
String s1 = "aaaaa";
String s2 = "aaaaa";
//在堆上开辟空间 这个堆上的地址中的value指向的是常量池中的数据
String s3 = new String("aaaaa");
String s4 = new String("aaaaa");
System.out.println(s1 == s2);//true
System.out.println(s3 == s4);//false //堆上的地址不一样
System.out.println(s1 == s3);//false
}
1.10 字符串的不可变性
String类中的字符实际保存在内部维护的value字符数组中
1. String类被final修饰,表名该类不能被继承
2. value被final修饰,表示value自身的值不能改变,既不能引用其它字符数组,但是其引用空间的内容可以被修改
3. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
1.11 字符串的修改
字符串的修改实际上是创建了新的对象
在循环中进行字符串拼接时,String在每次拼接时都是创建新的对象,很费时间
//在循环中进行字符串拼接时,String在每次拼接时都是创建新的对象,很费时间
//StringBuffer 和 StringBuilder是根据原来对象进行拼接
//在循环拼接字符串最好使用StringBuffer 和 StringBuilder
public static void test3() {
long start = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 100000; i++) {
s += i;
}
long end = System.currentTimeMillis();
System.out.println(end - start);//3019
start = System.currentTimeMillis();
StringBuffer s1 = new StringBuffer("");
for (int i = 0; i < 100000; i++) {
s1.append(i);
}
end = System.currentTimeMillis();
System.out.println(end - start);//3
start = System.currentTimeMillis();
StringBuilder s2 = new StringBuilder();
for (int i = 0; i < 100000; i++) {
s2.append(i);
}
end = System.currentTimeMillis();
System.out.println(end - start);//2
}
2. StringBuilder和StringBuffer
2.1 StringBuilder介绍
//String拼接的实质
public static void test4() {
String s1 = "abcd";
//循环内的相当于 s1 += i
//即String的拼接每次都会 创建一个新的对象以及两次拼接和一次转换
for (int i = 0; i < 100; i++) {
StringBuilder sb = new StringBuilder();
sb.append(s1);
sb.append(i);
s1 = sb.toString();//类型转换
}
System.out.println(s1);
//以上代码可以简化为如下
StringBuilder stringBuilder = new StringBuilder("abcd");
for (int i = 0; i < 100; i++) {
stringBuilder.append(i);
}
System.out.println(stringBuilder);
}
2.2 两者的主要区别
//StringBuffer 和 StringBuilder
public static void test5() {
StringBuilder stringBuilder = new StringBuilder("asdfghjkl");
//逆置字符串 String则没有这个方法
stringBuilder.reverse();
System.out.println(stringBuilder);
}