目录
一、字符串原理
1. 扩展底层原理1 : 字符串存储的内存原理
2. 扩展底层原理2:==号比较的到底是什么?
3. 扩展底层原理3:字符串拼接的底层原理
3.1 没有变量参与
3.2 有变量参与
4. 扩展底层原理4:StringBuilder提高效率原理图
4.1 常见面试题1
4.2 常见面试题2
5. 扩展底层原理5:StringBuilder源码分析
二、字符串综合练习
1. 转换罗马数字
2. 调整字符串
一、字符串原理
1. 扩展底层原理1 : 字符串存储的内存原理
- 直接赋值会复用字符串常量池中的
- new出来的不会复用,而是开辟一个新的空间
2. 扩展底层原理2:==号比较的到底是什么?
- 基本数据类型比较数据值
- 引用数据类型比较地址值
3. 扩展底层原理3:字符串拼接的底层原理
3.1 没有变量参与
拼接的时候没有变量,都是字符串。 触发字符串的优化机制。 | |
3.2 有变量参与
字符串拼接的时候有变量参与: 在内存中创建了很多对象 | |
结论: 如果很多字符串变量拼接,不要直接+。在底层会创建多个对象,浪费时间,浪费性能。 |
4. 扩展底层原理4:StringBuilder提高效率原理图
所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存。
StringBuilder是一个内容可变的容器 | |
思考: StringBuilder会被撑爆吗? (不会) |
4.1 常见面试题1
- 问题:下列代码的运行结果
- 答案: false ( s1记录的是串池中的地址值 , s3则是新new出来的对象)
字符串串拼接时候,如果有变量:
JDK8以前系统底层会自动创建一个StringBuilder对象,然后再调用其append方法完成拼接。拼接后,再调用其toString方法转换为String类型,而toString方法的底层是直接new了一个字符串对象。JDK8版本系统会预估要字符串拼接之后的总大小,把要拼接的内容都放在数组中,此时也是产生一个新的字符串。
4.2 常见面试题2
- 问题:下列代码的运行结果是?
- 答案: true (s1记录的是串池中的地址值 s2则是复用串池中的字符串)
在编译的时候,就会将"a" + "b" + "c" 拼接成"abc"
5. 扩展底层原理5:StringBuilder源码分析
- 默认创建一个长度为16的字节数组
- 添加的内容长度小于16,直接存
- 添加的内容大于16会扩容(原来的容量*2+2)
- 如果扩容之后还不够,以实际长度为准
public static void main(String[] args) {
//容量:最多存多少
//长度:已经存了多少
StringBuilder sb = new StringBuilder();
System.out.println(sb.capacity()); //16
System.out.println(sb.length()); // 0
sb.append("abc");
System.out.println(sb.capacity()); //16
System.out.println(sb.length()); // 3
sb.append("abcdefghijklmnopqrestuvwxyz");
System.out.println(sb.capacity()); //34
System.out.println(sb.length()); // 26
sb.append("abcdefghijklmnopqrestuvwxyz0123456789");
System.out.println(sb.capacity()); //36
System.out.println(sb.length()); // 26
}
二、字符串综合练习
1. 转换罗马数字
键盘录入一个字符串
要求1:长度为小于等于9
要求2:只能是数字
将内容变成罗马数字
下面是阿拉伯数字跟罗马数字的对比关系:
l - 1、ll - 2、Ⅲ- 3、IV - 4、V - 5、VI- 6、VII- 7、Ⅷ- 8、IX - 9注意点:
罗马数字里面是没有0的
如果键盘录入的数字包含0,可以变成””(长度为0的字符串)
public static void main(String[] args) {
// 1.键盘录入
Scanner sc = new Scanner(System.in);
String str;
while (true) {
System.out.println("请输入一个字符串:");
str = sc.next();
// 2.校验字符串是否满足需求
boolean flag = checkStr(str);
if (flag) {
break;
} else {
System.out.println("当前字符串不符合需求,请重新输入");
continue;
}
}
//3.将字符变成罗马数字
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
//字符变数字
char c= str.charAt(i); // '1' '2' '3'
int number = c -48; // 1 2 3
String s =changeStr(number);
// String s = changeStr(c);
sb.append(s);
}
System.out.println(sb);
}
//1.查找法
public static String changeStr(int number) {
//定义一个数组和罗马数字有对应关系
String[] arr = {"","Ⅰ","Ⅱ","Ⅲ","Ⅳ","Ⅴ","Ⅵ","Ⅶ","Ⅷ","Ⅸ"};
return arr[number];
}
2. switch法
// public static String changeStr(char number) {
// String str;
// switch(number) {
// case '0':str="";
// case '1':str="Ⅰ";
// case '2':str="Ⅱ";
// case '3':str="Ⅲ";
// case '4':str="Ⅳ";
// case '5':str="Ⅴ";
// case '6':str="Ⅵ";
// case '7':str="Ⅶ";
// case '8':str="Ⅷ";
// case '9':str="Ⅸ";
// default:str="";
// }
// return str;
// }
public static boolean checkStr(String str) {
// 需求1:长度小于或等于9
if (str.length() > 9) {
return false;
}
// 需求2:只能是数字
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
// 只有字符串中所有字符都判断完毕,才能任务字符串复合需求
return true;
}
运行结果:
2. 调整字符串
给定两个字符串,A和B。
A的旋转操作就是将A最左边的字符移动到最右边。
例如,若A = 'abcde',在移动一次之后结果就是'bcdea'。如果在若干次调整操作之后,A能变成B,那么返回True。
如果不能匹配成功,则返回false
public static void main(String[] args) {
// 1.定义两个字符串
String strA = "abcde";
String strB = "cdeab";
// 2.旋转字符串 调用方法进行比较
// abcde -> bcdea -> cdeab -> deabc ->eabcd
boolean result = check(strA, strB);
System.out.println(result);
}
public static boolean check(String strA, String strB) {
for (int i = 0; i < strA.length(); i++) {
strA = rotate(strA);
if (strA.equals(strB)) {
return true;
}
}
// 所有情况都比较完毕都不一样
return false;
}
// 选择字符串,把左侧字符移动到右侧去
// 形参:旋转前的字符串
// 返回值:旋转后的字符串
public static String rotate(String str) {
// 如果我们以后看到要修改字符串内容
// 1.用StringBuilder进行截取,把左侧字符截取出来拼接到右侧上
// 2.可以把字符中先编程一个字符数组,
// 然后调整字符数组里面数据,最后再把字符数组变成字符串
// 1.截取数组
// 截取最左侧字符
// char first = str.charAt(0);
// // 截取剩余字符
// String end = str.substring(1);
// return end + first;
// 2. 字符数组
char[] arr = str.toCharArray();
// 拿到0索引上的字符
char first = arr[0];
// 把剩余的字符依次往前挪一个位置
for (int i = 1; i < arr.length; i++) {
arr[i - 1] = arr[i];
}
// 把原来0 索引方法放到最后一个索引
arr[arr.length - 1] = first;
// 利用字符数组创建一个字符串对象
String result = new String(arr);
return result;
}