Java - 字符串

Java 字符串

1. 字符串的创建

字符串的创建和构造方法

1
2
3
4
5
6
7
8
9
10
// 直接创建
String str = "字符串";
// 根据传入字符串对象进行创建
String str = new String("字符串");
// 根据字符数组进行创建
char[] ch = {'字', '符', '串'};
String str = new String(ch);
// 根据字节数组进行创建
byte[] bytes = {97, 98, 99};
String str = new String(bytes);

1.1 字符串的内存模型

字符串的内存模型

在上述图中,当使用双引号直接赋值时,在栈内存中main方法执行了String s1 = "abc",JVM会先检查在堆内存
中的字符串常量池有没有”abc”
这个字符串,如果没有就会生成一个abc存放到字符串常量池中,并把地址值赋值给s1,在s2创建时,由于abc
已经在字符串常量池
中存在,所以会直接把地址值赋值给s2

字符串的内存模型

在上述图中,使用了字符数组的方式来创建字符串对象,由于字符数组引用数据类型它执行后会在堆内存
中开辟一个空间,并将地址返回给chs,当s1创建时传入chs地址值,它会对在堆内存中存储的字符数组生成一个全新的
String对象并将地址返回给s1s2的创建重复刚才的步骤,但s2的指向的字符串对象
跟s1指向的不一致,这个过程不会有地址值复用

1.2 字符串的常用方法

1.2.1 比较

1
2
3
4
5
6
7
String s1 = new String("abc");
String s2 = new String("abc");
if (s1 == s2) {
System.out.println("相等");
} else {
System.out.println("不相等"); // 不相等
}
1
2
3
4
5
6
7
String s3 = "abc";
String s4 = "abc";
if (s3 == s4) {
System.out.println("相等"); // 相等
} else {
System.out.println("不相等");
}

观察两个代码块可以发现,通过new出来的String对象,它会在堆内存中将字符串进行存储,从而分配两个不同的地址值分别赋值给 s1和s2变量,在控制语句中实际上是判断的地址值是否相等,因为在堆内存中是两个不同的地址,使用会输出不相等。

而第二个通过引号直接赋值的方式产生的String对象,它会将字符串存储到字符串常量池中,因为两次通过引号赋值是同一个字符串,所以s3和s4对象是被赋值同一个地址值,最后在控制语句中输出相等。

1.2.2 常用API

1
2
3
4
5
6
7
8
9
10
11
public int length​() // 获取字符串的长度返回(就是字符个数)
public char charAt​(int index) // 获取某个索引位置处的字符返回
public char[] toCharArray​() // 将当前字符串转换成字符数组返回
public boolean equals(Object anObject) // 判断当前字符串与另一个字符串的内容一样,一样返回true
public boolean equalsIgnoreCase(String anotherString) // 判断当前字符串与另一个字符串的内容是否一样(忽略大小写)
public String substring(int beginIndex, int endIndex) // 根据开始和结束索引进行截取,得到新的字符串(包前不包后)
public String substring(int beginIndex) // 从传入的索引处截取,截取到末尾,得到新的字符串返回
public String replace(CharSequence target, CharSequence replacement) // 使用新值,将字符串中的旧值替换,得到新的字符串
public boolean contains(CharSequence s) // 判断字符串中是否包含了某个字符串
public boolean startsWith(String prefix) // 判断字符串是否以某个字符串内容开头,开头返回true,反之
public String[] split(String regex) // 把字符串按照某个字符串内容分割,并返回字符串数组回来
1
2
3
4
5
6
// StringBuilder
StringBuilder builder = new StringBuilder(); // 创建一个StringBuilder对象
public StringBuilder append(String str) // 添加一个字符串对象进入到StringBuilder对象中
public int length() // 返回StringBuilder对象长度
public String toString() // 将StringBuilder对象以字符串的形式进行返回
public StringBuilder reverse() // 将StringBuilder进行反转
1
2
StringJoiner joiner = new StringJoiner("分割符","开始符号","结束符号");
public StringJoiner add(charSequence charsequence) // 给StringJoiner对象添加字符串进行存储

1.3 字符串原理小结

1.3.1 字符串存储的原理

  • 直接赋值会复用字符串常量池中的
  • new出来不会复用,而是开辟一个新的空间

1.3.2 ==号比较的到底是什么

  • 基本数据类型比较数据值
  • 引用数据类型比较地址值

1.3.3 字符串拼接的底层原理

  • 如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果,会复用字符串常量池
  • 如果有变量参与,会创建新的字符串对象,浪费内存

1.3.4 StringBuilder提高效率原理

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

1.3.5 StringBuilder扩容机制

  • 默认创建一个长度为16的字节数组
  • 添加的内容长度小于16,直接存储
  • 添加的内容大于16会扩容(原来的容量 * 2 + 2)
  • 如果扩容之后还不够,以实际长度为准

1.4 案例

已知正确的用户名和密码,请用程序实现模拟用户登录
总共给三次机会,登录之后给出相应的提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
已知正确的用户名和密码,请用程序实现模拟用户登录
总共给三次机会,登录之后给出相应的提示
*/
public static void main(String[] args) {
// 1. 定义正确的用户名和密码
String username = "zhangsan";
String password = "123456";
Scanner sc = new Scanner(System.in);
// 2. 模拟用户输入进行
for (int i = 0; i < 3; i++) {
System.out.println("请输入用户名");
String uName = sc.next();
System.out.println("请输入密码");
String uPwd = sc.next();
// 3.判断
if (username.equals(uName) && password.equals(uPwd)) {
System.out.println("登录成功");
break;
} else {
if (i < 2) {
System.out.println("用户名或密码不正确,还剩下" + (2 - i) + "次机会");
} else {
System.out.println("用户已被锁定");
}
}
}
}

键盘录入一个字符串,并在控制台中遍历该字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
public class StringTopic1 {
/**
* 键盘录入一个字符串,并在控制台中遍历该字符串
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
System.out.println(c);
}
}
}

键盘录入一个字符串,统计该字符串中大写字符、小写字符、数字字符的出现个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 public static void main(String[] args) {
int upperChar = 0;
int lowerChar = 0;
int digitChar = 0;
Scanner sc = new Scanner(System.in);
String str = sc.next();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c >= '0' && c <= '9') {
digitChar++;
} else if (c >= 'A' && c <= 'Z') {
upperChar++;
} else if (c >= 'a' && c <= 'z') {
lowerChar++;
}
}
System.out.println("大写字符出现了" + upperChar + "次");
System.out.println("小写字符出现了" + lowerChar + "次");
System.out.println("数字字符出现了" + digitChar + "次");
}
}

定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回
调用该方法并在控制台输出结果
例如:
数组为 int[] arr = {1,2,3};
输出结果: [1,2,3]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class StringTopic3 {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
String result = arrToString(arr);
System.out.println(result);
}

public static String arrToString(int[] arr) {
// 对数组的长度和地址进行判断
if (arr == null) {
return "";
}
if (arr.length == 0) {
return "";
}
// 定义最终存放的字符串
String result = "[";
// 遍历数组
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
result += arr[i];
} else {
result += arr[i] + ",";
}
}
return result + "]";
}
}

定义一个方法 反转一个字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class StringTopic4 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String reverse = reverse(sc.next());
System.out.println(reverse);
}

public static String reverse(String str) {
String result = "[";
for (int i = str.length() - 1; i >= 0; i--) {
result += str.charAt(i);
}
return result + "]";
}
}

从键盘接入一个用户输入的值
例如: 2135
定义一个方法
将它转换为大写中文字符
如:零佰零拾零万贰仟壹佰叁拾伍元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class StringTopic5Mirror {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int value = sc.nextInt();
// 判断值是否处于合理范围

while (true) {
if (value > 0 && value < 9999999) {
break;
} else {
System.out.println("输入的值不合理请重新输入");
}
}
String valueStr = "";
while (true) {
// 取出数值的个位数
int bit = value % 10;
valueStr = conversion(bit) + valueStr;
value = value / 10;
if (value == 0) {
break;
}
}
// System.out.println(valueStr);
// 将值转换为大写中文字符

int count = 7 - valueStr.length();
// 将字符串进行补零
for (int i = 0; i < count; i++) {
valueStr = "零" + valueStr;
}


String arr[] = {"佰", "拾", "万", "仟", "佰", "拾", "元"};
String result = "";
for (int i = 0; i < arr.length; i++) {
char ch = valueStr.charAt(i);
result += ch + arr[i];
}
System.out.println(result);
}

public static String conversion(int value) {
String arr[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
return arr[value];
}
}

定义一个手机号码,把中间的号码进行隐藏处理
例如: 定义 13112349841 输出 131****9841

1
2
3
4
5
6
7
8
9
public class StringTopic6 {
public static void main(String[] args) {
String phoneNumber = "13112349841";
String start = phoneNumber.substring(0, 3);
String end = phoneNumber.substring(7);
String authenticNumber = start + "****" + end;
System.out.println(authenticNumber);
}
}

根据身份证信息来输出相关出生日期和性别
例如 420111200005011259
输出 出生日期为: 2000年05月01日 性别为男

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class StringTopic7 {
public static void main(String[] args) {
String id = "420111200005011259";
String year = id.substring(6, 10);
String month = id.substring(10, 12);
String day = id.substring(12, 14);
System.out.println("出生日期为:" + year + "年" + month + "月" + day + "日");
char gender = id.charAt(16);
int flag = gender - 48;
// System.out.println(flag);
if (flag % 2 == 0) {
System.out.println("性格为女");
} else {
System.out.println("性格为男");
}
}
}

屏蔽词替换

1
2
3
4
5
6
7
8
9
10
11
public class StringTopic8 {
public static void main(String[] args) {
String shield[] = {"派蒙", "旅行者", "原神"};
String talk = "派蒙不知道哦";
for (int i = 0; i < shield.length; i++) {
talk = talk.replace(shield[i], "***");
}
System.out.println(talk);
}
}

键盘接入一个字符串,判断它们是否为对称字符串,并在控制台打印是或不是

1
2
3
4
5
6
7
8
9
10
11
12
public class StringBuilderTopic1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
StringBuilder builder = new StringBuilder(str);
if (builder.reverse().toString().equals(str)) {
System.out.println("是");
} else {
System.out.println("不是");
}
}
}

定义一个方法,把int数组中的数据安装指定的格式拼接成一个字符串返回
调用该方法,并在控制台输出结果
例如 数组为int[] arr = {1,2,3}
执行方法后的输出结果为: [1,2,3]

1
2
3
4
5
6
7
8
9
10
11
public class StringBuilderTopic2 {
public static void main(String[] args) {
int arr[] = {1, 2, 3};
System.out.println(splicing(arr));
}

public static String splicing(int[] arr) {
StringBuilder builder = new StringBuilder();
return builder.append(Arrays.toString(arr)).toString();
}
}

键盘录入一个字符串
要求1:长度为小于等于9
要求2:只能是数字
将内容变成罗马数字
1-Ⅰ、2-Ⅱ、3-Ⅲ、4-Ⅳ、5-Ⅴ、6-Ⅵ、7-Ⅶ、8-Ⅷ、9-Ⅸ
注意点:
罗马数字是没有0的
如果键盘录入的数字包括0,可以变成””(长度为0的字符串)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class StringTopic1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str;
while (true) {
System.out.println("输入一个字符串:");
str = sc.next();
boolean flag = verify(str);
if (flag) {
break;
} else {
System.out.println("当前字符串不符合规则 请重新输入");
}
}

StringJoiner joiner = new StringJoiner(",", "[", "]");
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
int number = c - 48;
joiner.add(conversion(number));
}

System.out.println(joiner.toString());

}

public static String conversion(int number) {
String arr[] = {"", "Ⅰ", "Ⅱ", "Ⅲ", "Ⅳ", "Ⅴ", "Ⅵ", "Ⅶ", "Ⅷ", "Ⅸ"};
return arr[number];
}

public static boolean verify(String str) {
if (str.length() > 9) {
return false;
}

for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
return true;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class StringTopic1Mirror {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = "";
System.out.println("输入一个字符串:");
while (true) {
str = sc.next();
boolean flag = verify(str);
if (flag) {
break;
} else {
System.out.println("输入值有误");
}
}

StringJoiner joiner = new StringJoiner(",", "[", "]");
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
String temp = String.valueOf(c);
int value = Integer.parseInt(temp);
joiner.add(conversion(value));
}
System.out.println(joiner.toString());

}

private static String conversion(int value) {
String arr[] = {"", "Ⅰ", "Ⅱ", "Ⅲ", "Ⅳ", "Ⅴ", "Ⅵ", "Ⅶ", "Ⅷ", "Ⅸ"};
return arr[value];
}

private static boolean verify(String str) {
if (str.length() > 9) {
return false;
}

for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
String temp = String.valueOf(c);
int value = Integer.parseInt(temp);
if (value < 0 || value > 9) {
return false;
}
}
return true;

}
}

给定两个字符串,A和B
A的旋转操作就是将A 最左边的字符移动到最右边
例如,若 A = “abcde” B = “cdeab”, 在移动一次后的结果就是 “bcdea”
如果在若干次调整操作之后 若 A能变成B 则返回 True
如果不能匹配成功则返回false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class StringTopic2 {
public static void main(String[] args) {
String strA = "abcde";
String strB = "cdeab";

boolean flag = check(strA, strB);
if (flag) {
System.out.println("匹配成功");
} else {
System.out.println("匹配失败");
}
}

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) {
char first = str.charAt(0);
String end = str.substring(1);
return end + first;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class StringTopic2Mirror {
public static void main(String[] args) {
String strA = "abcde";
String strB = "cdeab";

boolean flag = check(strA, strB);
if (flag) {
System.out.println("匹配成功");
} else {
System.out.println("匹配失败");
}
}
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) {
char first = str.charAt(0);
char[] array = str.toCharArray();
for (int i = 1; i < array.length; i++) {
array[i - 1] = array[i];
}
array[array.length - 1] = first;
return new String(array);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
键盘录入一个字符串,打乱字符串里面的内容
```java
public class StringTopic3 {
public static void main(String[] args) {
String str = "abcdefg";
char[] array = str.toCharArray();
Random r = new Random();
int number = 0;
for (int i = 0; i < array.length; i++) {
number = r.nextInt(array.length);
array[i] = array[number];
}
String result = new String(array);
System.out.println(result);
}
}

生成验证码
内容:可以是小写字母,也可以是大写字母,还可以是数字
规则
长度为5
内容中是四位数字,一位数字
其中数字只有1位,但是可以出现在任意位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class StringTopic4 {
public static void main(String[] args) {
char[] arr = new char[52];
for (int i = 0; i < 26; i++) {
arr[i] = (char) ('a' + i);
}

int temp = 0;
for (int i = 26; i < arr.length; i++) {
arr[i] = (char) ('A' + temp);
temp++;
}

StringBuilder builder = new StringBuilder();
Random r = new Random();
int randomNumber = 0;
int i = 0;
while (i < 4) {
randomNumber = r.nextInt(arr.length);
builder.append(arr[randomNumber]);
i++;
}
builder.append(r.nextInt(10));

char temporary;
String value = builder.toString();
char[] array = value.toCharArray();
randomNumber = r.nextInt(array.length - 1);
temporary = array[randomNumber];
array[randomNumber] = array[array.length - 1];
array[array.length - 1] = temporary;
String result = new String(array);
System.out.println(result);

}
}

给定两个字符串形式表示的非负整数num1和num2,返回num1和num2的乘积,它们的乘积表示为字符串的形式
注意:需要使用已有的知识进行完成
不需要考虑乘积过大的后果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class StringTopic5 {
public static void main(String[] args) {
String num1 = "123";
String num2 = "654";
int number1 = conversion(num1);
int number2 = conversion(num2);
System.out.println(number1 * number2);
}

public static int conversion(String str) {
int result = 0;
int arr[] = new int[9];
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
arr[i] = toInteger(c);
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
break;
} else {
result = result * 10 + arr[i];
}
}
return result;
}

public static int toInteger(char ch) {
int[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int temp = ch - 48;
return arr[temp];
}

}

给你一个字符串 s 由若干单词组成,单词前后用一些空格隔开
返回字符串中最后一个单词的长度
单词仅由字母组成、不包含任何空格字符的最大子字符串
示例1
输入 s = “Hello World” 输出:5

1
2
3
4
5
6
7
8
9
10
11
12
13
public class StringTopic6 {
public static void main(String[] args) {
String s = "Hello World";
int count = 0;
for (int i = s.length() - 1; i > 0; i--) {
if (s.charAt(i) == 32) {
break;
}
count++;
}
System.out.println(count);
}
}