String字符串简介
-
概述
String是Java里的一个类,属于引用类型,遵循引用类型的基本规律和要求。但它也有自己的一些特点,比如可以直接用双引号"......"来表示一个字符串,所以凡是用双引号括起来的一串字符都是String对象,如“Hello”在编译后就会成为一个String对象。另外从名字上我们也可以猜测出,字符串与字符有一定的关系。所以我们可以通过如下方式来表示一个字符串:
String name = "Hello World"; -
注意点
字符串内容是不会发生改变的,它的对象在创建后不能被更改。
凡是有字符串参与拼接的都会产生一个新的字符串。
String hello1 = "Hello"; String hello2 = "World"; System.out.println(hello1 + hello2); // 产生新的字符串
String字符串创建
-
String字符串的定义方式,常用的有如下两种:
- 直接赋值:
String s1 = "Hello World!"; System.out.println(s1);2. 通过构造方法创建字符串对象
构造方法 说明 public String() 创建空白字符串,不含任何内容 public String(Syting original) 根据传入的字符串,创建字符串对象 public String(char[] chs) 根据字符数组,创建字符串对象 public String(byte[] chs) 根据字节数组,创建字符串对象 // 空参构造:创建一个空白的字符串对象 String s2 = new String(); System.out.println("s2" + s2 + "!"); // s2! // 传递一个字符串,根据传递的字符串内容创建一个新的字符串对象。 String s3 = new String("abc"); System.out.println(s3); // abc // 传递一个字符数组,根据传递的字符数组内容创建一个新的字符串对象。 char[] chars = {'a','b','c'}; String s4 = new String(chars); System.out.println(s4); // abc // 传递一个字节数组,根据传递的字节数组内容创建一个新的字符串对象。 // 拿着这个数字到ASCII表中去找对应的字母进行拼接 byte[] bytes = {97,98,99,100}; String s5 = new String(bytes); System.out.println(s5); // abcd我们在开发时,其实很少使用第二种方式,因为太过啰嗦,一般都是通过直接赋值的方式进行定义。
String字符串内存原理
-
1.直接赋值:当使用双引号直接赋值时,系统会检查该字符串在串池是否存在。
如果不存在就创建新的,如果存在就直接复用。
-
2.创建赋值:
char[] chs = {'a','b','c']; String s1 = new String(chs); String s2 = new String(chs);首先main方法进栈,先执行第一行代码。此时就创建出了一个char类型的数组,数组在堆里面开辟了一个新的地址值0x0011并赋值给chs。然后来执行第二行代码,第二行代码等号右边是new出来的,所以在对空间也开辟了一个空间,此时空间的内容是abc,然后把地址值0x0022赋值给s1,第三行的代码其实也是和上面一样,重复执行了一次而已。
String字符串实用方法案例
1. 字符串的比较方法
下面我们来说一下==号比的到底是什么,我们往下看:
- 基本数据类型:
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2); // true
- 引用数据类型:
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // false
s1不是等于s2吗?怎么是false呢?
我们来回想一下,等号右边是什么,是不是new呀,new出来的是不是一个地址值呢?两个地址值肯定不一样呀,所以是false。那这里我们可以得出一个结论啦:
-
基本数据类型比较的是数据值。
-
引用数据类型比较的是地址值。
我们再来看一段代码:
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2); // false
这个为什么也是false呢?我们来回想一下,s1是不是new出来的呢?所以是存放在堆空间里面的地址值,而s2是直接赋值的,字符串直接赋值是不是存储在串池里面的地址值呀,两个地方都不一样,所以说也是false啦。
那我如果就是想要比较内容怎么办呢?难道没办法比较吗?
肯定不是啦,在Java中,如果我们想比较两个字符串,其实有两个比较方法:
| 方法 | 说明 | 使用场景 |
|---|---|---|
| boolean equals()方法 | 完全一样结果才为true,否则为false | 密码验证 |
| boolean equalslgnoreCase()方法 | 忽略大小写进行比较 | 验证码验证 |
我们来实操一下吧:
// 1.创建两个字符串对象进行比较
String s1 = new String("abc");
String s2 = "ABC";
// 2.==号比较
// 基本数据类型,比的是数据值
// 引用数据类型,比的是地址值
System.out.println(s1 == s2); // false
// 3.比较字符串对象中的内容是否相等
boolean result = s1.equals(s2);
System.out.println(result); // false
// 4.比较字符串对象中的内容是否相等,忽略大小写
boolean result1 = s1.equalsIgnoreCase(s2);
System.out.println(result1); // true
那这个时候有人就在想了,equalsIgnoreCase() 方法不是忽略大小写吗,那我输入1,一,壹他是不是也能判断相同呀?其实这不行。忽略大小写只能忽略英文的大小写。
我们来看一个验证密码的案例吧:
需求:已知正确用户名和密码,请用程序实现模拟用户登录。 总共给3次机会,登录之后,给出相对应的提示。
第一步:定义正确的用户名和密码
String rightUserName = "zhangsan";
String rightUserPassWord = "123456";
第二步:键盘输入用户名。
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String userName = sc.next();
第三步:如果正确就进行判断密码,错误就重新输入
if(userName.equals(rightUserName)){
System.out.println("您的用户名正确!");
}else{
System.out.println("您的用户名错误!");
}
第四步:验证密码并提示。
System.out.println("请输入密码:");
String userPasssWord = sc.next();
if(userPasssWord.equals(rightUserPassWord)){
System.out.println("登录成功!");
}else{
if(i == 2){
System.out.println("您的用户名" + rightUserName + "已被锁定");
}else{
System.out.println("您的密码错误!还剩下" + (2 - i) + "次机会!");
}
}
我们来运行看一下吧:
下面我们来总结一下字符串比较的注意事项有哪些吧:
-
比较注意事项:
1.比较两个字符串的内容是否相同,应该使用 equals() 和 equalslgnoreCase方法 方法,而不要使用 == 进行比较。
2.equalsIgnoreCase()比较方法只能忽略英文的大小写。
2. 字符串的遍历
我们先来说一下获取字符串的4种方法吧!
| 方法 | 说明 |
|---|---|
| char charAt(int index) | 获取指定下标位置上对应的字符,并返回char类型 |
| int length() | 该方法用于返回字符串对象中包含的字符数量,即可以获取字符串的长度 |
| 数组名.lenght | 获取数组的长度 |
| 字符串对象.lenght() | 获取字符串的长度 |
我们来看一下常用的遍历吧:
// 1.键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = sc.next();
// 2.字符串的遍历
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
System.out.print(c + " ");
}
怎么样是不是和数组的遍历是一样的呀!
3. 字符串的截取
| 方法 | 说明 | 规则 |
|---|---|---|
| String substring(start,end) | 截取 | 包头不包尾,包左不包右 |
| String substring(index) | 截取 | 默认截取到末尾 |
String substring(start,end):截取范围
String phoneNumber = "13111111111";
// 截取手机号码的前3位
String start = phoneNumber.substring(0, 3);
System.out.println(start); // 131
String substring(index):截取到末尾
// 截取手机号码后面四位
String end = phoneNumber.substring(7);
System.out.println(end); // 1111
-
这里我们需要注意一下:
-
substring(start,end):包头不包尾,包左不包右。
-
String substring(index):表示从索引开始位置一直截取到末尾的全部。
-
4. 字符串的替换
什么是替换呢?我们来看下面这张图片:
他是不是把一些字给替换成星号了呢,你能猜到是什么字吗?那肯定是敏感词呀对不对,那这些是怎么替换的呢我们接着往下看。
| 方法 | 说明 | 规则 |
|---|---|---|
| String replace(旧值,新值) | 替换 | 将旧值替换成新值 |
我们来实操一下吧:
// 1.定义一个字符串
String str = "你玩的很好,以后不要在玩了,TMD";
// 2.把里面的敏感词替换为星号
String result = str.replace("TMD","***");
System.out.println(result);
是不是成功把敏感词给替换为星号了呀!
5. 字符串的切割
| 方法 | 说明 | 规则 |
|---|---|---|
| String split(): | 切割 | 按照指定的字符串对原字符串进行切割 |
| 我们来举个例子: |
//字符串切割,按照指定的字符串对原字符串进行切割
String s1 = "zhangsan——lisi——wangwu";
//利用指定的分隔符进行分割,比如利用“——”进行切割
String[] s = s1.split("——");
System.out.println(Arrays.toString(s));
我们运行看一下吧:
是不是都以逗号隔开了呀!
6. 字符串的大小写转换
| 方法 | 说明 |
|---|---|
| String toUpperCase(): | 将字符串的字母全部转为大写 |
| String toLowerCase() | 将字符串的字母全部转为小写 |
// 字符串大小写转换
String s2 = "abc嘿嘿嘿ABC";
// 将字符串的字母全部变成大写
String s3 = s2.toUpperCase();
System.out.println(s3);
// 将字符串的字母全部变成小写
String s4 = s2.toLowerCase();
System.out.println(s4);
我们运行看一下效果:
好啦,以上这些方法,就是String字符串中的一些常用方法,当然并不是全部的方法。实际上,String中还有其他的一些方法不是很常用,这里就不再一一列出来啦。
StringBuilder
StringBuilder是什么?为什么要学习StringBuilder呢?
我们来看段代码:
String s = "";
for (int i = 0; i < 1000000; i++) {
s += "abc";
}
System.out.println(s);
我们来循环拼接这个字符串,我们运行看一下:
可以看到要循环很多次,也需要非常久的时间才能循环拼接完。
那有没有什么方法不用等,可以直接拼接完毕的吗?答案是有的,我们接着看使用StringBuilder方法:
StringBuilder s = new StringBuilder(" ");
for (int i = 0; i < 1000000; i++) {
s.append("abc");
}
System.out.println(s);
我们运行看一下:
怎么样,是不是秒拼接生成了呢?那下面我们就来说一下什么是StringBuilder吧:
StringBuilder概念
-
StringBuilder可以看成是一个容器,创建之后里面的内容是可以变的。
- 作用:提高字符串的操作效率。
String s1 = "aaa";
String s2 = "bbb";
String s3 = "ccc";
String s4 = "ddd";
String s5 = "eee";
我们使用StringBuilder呢就可以直接装进去了。
下面我们来说一下StringBuiler构造方法吧!
StringBuilder构造方法
| 方法名 | 说明 |
|---|---|
| public StringBuilder() | 创建一个空白可变的字符串对象,不含有任何内容 |
| public StringBuilder(String str) | 根据字符串内容,来创建可变的字符串对象 |
-
StringBuilder空参构造:
StringBuilder s1 = new StringBuilder();
-
StringBuilder有参构造:
StringBuilder s1 = new StringBuilder("ABC");
构造方法我们就讲完了,下面我们来说一下常用方法吧:
StringBuilder成员方法
| 方法名 | 说明 |
|---|---|
| public StringBuilder append(任意类型) | 添加数据,并返回对象本身 |
| public StringBuilder reverse() | 反转容器中的内容 |
| public int lenght() | 返回长度(字符出现的个数) |
| public String toString() | 通过toString()就可以实现把StringBuilder转换为String |
是不是感觉有点蒙蒙的,没事,我们把他们全部实操一下吧:
- StringBuilder append(任意类型)拼接方法:
// 1.创建对象
StringBuilder s1 = new StringBuilder("abc");
// 2.添加元素
s1.append(1);
s1.append(8.8);
s1.append(false);
// 打印
System.out.println(s1);
我们运行可以看到是不是全部都拼接在字符串后面了呀!
- StringBuilder reverse()反转方法:
// 3.反转
s1.reverse();
他是在容器内直接反转了,和字符串不一样,字符串本身是不能发生变化的,只有返回值才可以替换或者截取的。
- int lenght()方法:
// 4.获取长度
int len = s1.length();
- String toString()方法:
// 1.创建对象
StringBuilder s1 = new StringBuilder();
// 2.添加字符串
s1.append("aaa").append("bbb").append("ccc").append("ddd");
// 3.再把StringBuilder变回字符串
String str = s1.toString();
System.out.println(str);
toString表示把容器内StringBuilder拼接的东西变成字符串返回一个字符串。
-
StringBuilder总结:
1.StringBuilder是用来帮助我们去操作字符串非常快捷的工具。
2.StringBuilder是Java已经写好的东西,打印对象不是地址值,而是属性值。
3.使用场景:字符串拼接、字符串反转。
StringJoiner
什么是StringJoiner?为什么要学习StringJoiner呢?
我们还是先来看段代码:
public static String arrTostring(int[] arr){
StringBuilder s1 = new StringBuilder();
s1.append("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length -1){
s1.append(arr[i]);
}else{
s1.append(arr[i]).append(",");
}
}
s1.append("]");
return s1.toString();
}
这个案例拼接字符串是不是很麻烦呀,要这里拼一块那里拼一块,那我就在想,有没有一种更方便快捷的方法呢?
肯定是有的呀,下面我们来体验一下StringJoiner吧:
StringJoiner概念
-
StringJoiner可以看成是一个容器,创建之后里面的内容是可以变的。
- 作用:提高字符串的操作效率,而且代码编写特别简洁。
StringJoiner构造方法
| 方法名 | 说明 |
|---|---|
| public StringJoiner(间隔符号) | 创建一个StringJoiner对象,指定拼接时的间隔符号 |
| public StringJoiner(间隔符号,开始符号,结束符号) | 创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号、结束符号 |
- 创建对象的第一种方法:
- 创建对象的第二种方法:
StringJoiner成员方法
| 方法名 | 说明 |
|---|---|
| public StringJoiner add(添加的内容) | 添加数据,并返回对象本身 |
| public int lenght() | 返回长度(字符出现的个数) |
| public String toString() | 返回一个字符串(该字符串就是拼接之后的结果) |
- StringJoiner(间隔符号)方法:
我们先来创建一个对象:
可以看到他报错了,这里就表示StringJoiner是没有空参构造的,所以需要传一个字符进去。 我们来看一下吧:
// 1.创建一个对象,并指定中间的间隔符号
StringJoiner s1 = new StringJoiner(",");
// 2.添加元素
s1.add("aaa").add("bbb").add("ccc");
// 3.打印
System.out.println(s1);
这个时候运行看一下:
怎么样,是不是按照我们指定的间隔符号进行间隔了呀!
- StringJoiner(间隔符号,开始符号,结束符号):
// 1.创建一个对象,并指定中间的间隔符号
StringJoiner s1 = new StringJoiner(",","[","]");
// 2.添加元素
s1.add("aaa").add("bbb").add("ccc");
System.out.println(s1);
我们来运行看一下:
是不是就自动添加了开始符号和间隔符号以及结束符号了呀!如果我们忘记这三个符号是哪个位置了怎么办呢?没关系,我们可以一个一个试嘛,对吧!
- int lenght()方法:
// 3.获取长度
int len = s1.length(); // 13
是不是直接就获取到字符串的长度了呢,和StringBuilder是一样的呢!
- String toString()方法:
// 4.toString
String str = s1.toString();
System.out.println(str); // [aaa,bbb,ccc]
可以看到它返回的也是一个字符串,是不是也和StringBuilder转换成字符串一样的呢!
- 到这里我们就学完String、StringBuilder、StringJoiner这三个啦,我们来说一下他们的区别吧:
- String:表示字符串的类,定义了很多操作字符串的方法。
- StringBuilder:一个可变的操作字符串的容器,可以高效的拼接字符串,还可以反转。
- StringJoiner:一个可变的操作字符串的容器,可以更高效,方便的拼接字符串。在拼接的时候,可以指定间隔符号、开始符号、结束符号。
字符串原理
字符串存储的内存原理
- 直接赋值会复用字符串常量池中的数据
- new出来不会复用,而是开辟一个新的空间
==号比较的是什么
- 基本数据类型:比较数据值是否相同
- 引用数据类型:比较的是地址值是否相同
字符串拼接底层原理
我们来看第一种情况:
String s = "a" + "b" + "c";
System.out.println(s);
如果是拼接的时候没有变量,都是字符串,那么就会触发字符串的优化机制。在编译的时候就已经是最终的结果了!
我们再来看第二种情况:
String s = "a";
String s1 = s + "b";
String s2 = s1 + "c";
System.out.println(s2);
如果是拼接的时候有变量参与,那么底层会使用StringBuilder,在内存中会创建多个对象,浪费空间,时间也非常慢。
结论:如果很多字符串变量拼接,不要直接+。因为在底层会创建很多个对象,浪费时间,浪费性能。
-
我们来小结一下吧:
- 如果没有变量参与,都是字符串直接相加,编译之后就是拼接的结果,会复用串池的字符串。
- 如果有变量参与,每一行拼接的代码,都会在内存中创建新的字符串,浪费内存。
StringBuilder提高效率原理图
我们来看段代码:
StringBuilder s1 = new StringBuilder();
s1.append("a");
s1.append("b");
s1.append("c");
System.out.println(s1);
我们还记得StringBuilder是什么吗?是不是一个内容可变的容器呀!
我的答案是:没有达到2147483648都不会爆。
难道我无限添加也不会爆吗?不是的,我们来看一下源码:
这是什么意思呢?
表示你的长度如果大于int类型的最大容量21亿多的话就会爆了。
-
我们来小结一下吧:
- 所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存。
StringBuilder源码分析
- 默认创建一个长度为16字节的数组。
- 添加的内容长度小于16,直接存。
- 添加的内容大于16就会扩容(原来的容量*2+2)。
- 如果扩容之后还不够,就以实际长度为准。
好啦,以上就是String字符串的一些常用方法和一些案例。有什么不懂的可以在评论区评论哟!我们下期再见!
==最后非常感谢您的阅读,也希望能得到您的反馈 ==