目录

一、字符串原理

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  没有变量参与 

java字符串低字节_java

拼接的时候没有变量,都是字符串。

触发字符串的优化机制。
在编译的时候已经是最终的结果了。

java字符串低字节_System_02

 3.2 有变量参与

java字符串低字节_字符串_03

字符串拼接的时候有变量参与:

在内存中创建了很多对象
浪费空间,时间也非常慢
 

java字符串低字节_System_04

结论:

如果很多字符串变量拼接,不要直接+。在底层会创建多个对象,浪费时间,浪费性能。

 4.  扩展底层原理4:StringBuilder提高效率原理图

所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存。

java字符串低字节_字符串_05

StringBuilder是一个内容可变的容器

java字符串低字节_System_06

思考: 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;
	}

 运行结果:

java字符串低字节_System_07

 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;

	}