一、String概述
java.lang.String类代表字符串,java中所有字符串文字都是该类的对象
字符串的内容是不会发生变化的,它的对象在创建之后就不能被更改
二、创建String对象
1、直接赋值
语法:
String 变量名=内容;
2、使用构造方法
语法1:
String 变量名=new String();
语法2:
String 变量名=new String(字符串);
语法3:
String 变量名=new String(字符数组);
语法4:
String 变量名=new String(字节数组);
public class StringDemo {
public static void main(String[] args) {
// 1.直接创建
String s1="你好java";
System.out.println(s1);
// 2.使用new的方式来获取一个字符串
// 使用空参构造方法创建空字符串
String s2=new String();
System.out.println("x"+s2+"!"); // s2是一个空白字符串
// 传递一个字符串 使用非空参构造创建字符串
// 这种方法与直接创建效果一样 没有必要用
String s3=new String("abc");
System.out.println(s3); // s3: abc
// 传递一个数组 根据数组的内容进行拼接再创建一个字符串
char [] chs={'a','b','c'};
String s4=new String(chs);
System.out.println(chs); // s4:abc
// 传递一个字节数组 根据数组内容再创建一个新的字符串对象
// 字符串的内容是由数组内容对应在ascii码值的字符组成
// 在本例中ascii码值为97对应的字符为a 98为b 99为c
byte [] bytes={97,98,99};
String s5=new String(bytes);
System.out.println(s5); // s5: abc
}
}
三、串池
当使用双引号直接赋值时,系统会检测字符串在串池中是否存在,如果不存在,则创建新的字符串,如果存在则复用该字符串
因此直接赋值比new更能节省空间
四、字符串的比较
实现字符串内容的比较:
1、boolean equals(要比较的字符串)
语法:字符串1.equals(字符串2)
完全一样的结果才是true ,否则为false
2、boolean equalslgnorecase(要比较的字符串)
语法:字符串1.equalsIgnoreCase(字符串2)
忽略大小写的比较(忽略的是英文状态下的大小写 中文状态下的大小写不能忽略 e.g:一 壹 不能认为相同)
public class 字符串的比较 {
public static void main(String[] args) {
String s1=new String("abc");
String s2="abc";
System.out.println(s1==s2);
boolean result1=s1.equals(s2);
System.out.println("s1.equals(s2)的结果是"+result1);
boolean result2=s1.equalsIgnoreCase(s2);
System.out.println("s1.equalsIgnoreCase(s2)的结果是"+result2);
}
}
// 输出结果:
// false
// s1.equals(s2)的结果是true
// s1.equalsIgnoreCase(s2)的结果是true
import java.util.Scanner;
public class 字符串的比较 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in); //创建Scanner类对象sc
String s1=sc.next(); // 从键盘录入的字符串 也是new出来的
String s2="abc"; // 直接赋值的字符串
System.out.println(s1==s2); // 因此两者的地址是不一样的
}
}
五、字符串的遍历
1、字符串长度:字符串对象.length()
注意区分 数组的长度是:数组名.length
2、获取索引对应的字符:字符串对象.charAt(索引)
public class 遍历字符串 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个字符串");
String s=sc.next();
// for循环的简便写法:s.length().fori
for (int i = 0; i < s.length(); i++) {
// 获取i索引对应的字符
System.out.println(s.charAt(i));
}
}
}
六、字符串的截取
截取多个字符用字符串.substring,截取一个字符用字符串.charAt
1、字符串.substring(int beginindex ,int endindex)
从beginindex索引开始截取到endindex结束,不包含endindex
2、字符串.substring(int beginindex)
从beginindex索引开始一直截取到末尾
public class test {
public static void main(String[] args) {
// 1.字符串.substring(int beginindex ,int endindex)
// 其返回值是截取之后的字符串
// 注意:被截取的字符串不会发生变化 因为字符串是不可变的
String phonenumber="19173239796";
String phonenumber1=phonenumber.substring(0,3); // 从索引0开始截取一直到索引3 不包括索引3
System.out.println(phonenumber);// 19173239796
System.out.println(phonenumber1);// 191
// 2.字符串.substring(int beginindex)
String phonenumber2=phonenumber.substring(7);
System.out.println(phonenumber);// 19173239796
System.out.println(phonenumber2);// 9796
}
}
七、字符转化为数字、字符串转为字符数组、字节数组
1、字符转化为数字
字符-48即可得到对应的数字
2、字符串转为字符数组
语法:字符串名.toCharArray();
3、字符串转为字节数组
语法:字符串名.getBytes();
public class 字符串转化 {
public static void main(String[] args) {
String str="abc";
// 字符串转化为字符数组
char [] arr1=str.toCharArray();
for (int i = 0; i < arr1.length; i++) {
System.out.print(arr1[i]+" ");
}// 输出: a b c
System.out.println();
// 字符串转化为字符数组
byte [] arr2=str.getBytes();
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i]+" ");
}// 输出: 97 98 99
}
}
八、字符串的替换
字符串.replace(旧值,新值);
有返回值,返回的是替换后的字符串,原字符串不会发生变化
public class test1 {
public static void main(String[] args) {
// 1.字符串.replace(旧字符串,新字符串)
String oldstr="菜就多练,TMD";
String newstr=oldstr.replace("TMD","***");
System.out.println(oldstr);
System.out.println(newstr);
// 输出:
// 菜就多练,TMD
// 菜就多练,***
// 2.有多个要替换的字符串 就将要替换的字符串放在一个字符数组中 遍历字符数组进行替换即可
String talk="菜就多练,TMD,wk";
String [] str={"wk","wc","TMD"};
for (int i = 0; i < str.length; i++) {
talk=talk.replace(str[i],"***");
}
System.out.println(talk);
// 输出:
// 菜就多练,***,***
}
}
九、修改字符串内容
1、通过subString进行裁剪然后拼接
2、将字符串转化为字符数组,调整字符数组的内容,再将调整好的字符数组转化为字符串
十、StringBuilder
概述:
StringBuilder是一个容器,创建之后里面的内容是可变的
对字符串进行操作时,我们可以将字符串转化为StringBuilder容器,能更加方便操作,最后将StringBuilder容器转化为字符串即可
StringBuilder是一个类,因此创建它的对象同样需要通过构造方法
1、StringBuilder构造方法
空参构造:
public StringBuilder();
创建一个空白可变字符串对象
带参构造:
public StringBuilder(String str);
根据字符串内容,创建可变字符串对象
public class test2 {
public static void main(String[] args) {
StringBuilder sb=new StringBuilder();
System.out.println(sb);
// 没有任何输出结果 并不会输出地址值
// 因为StringBuilder是java已经写好的类 系统对其进行了处理
// 它的结果输出的是属性值(即容器中存放的数据) 而不是地址值
StringBuilder sb1=new StringBuilder("abc");
System.out.println(sb1);// 输出:abc
}
}
2、StringBuilder成员方法
1、StringBuilder容器名.append(任意类型)
作用:添加数据,并返回对象本身(仍是StringBuilder类型)
public class test2 {
public static void main(String[] args) {
StringBuilder sb=new StringBuilder("abc");
sb.append(1);// 添加整数
sb.append(2.3);// 添加浮点数
sb.append('a');// 添加字符
sb.append(true);// 添加布尔值
sb.append("你好");// 添加字符串
System.out.println(sb);// 输出:abc12.3atrue你好
}
}
2、StringBuilder容器名.reverse()
作用:反转容器里面的内容 返回的仍是StringBuilder类型
注意:直接在容器内部反转 而不是将反转的内容存放在新的容器中
public class test2 {
public static void main(String[] args) {
StringBuilder sb=new StringBuilder("abc");
sb.append(1);// 添加整数
sb.append(2.3);// 添加浮点数
sb.append('a');// 添加字符
sb.append(true);// 添加布尔值
sb.append("你好");// 添加字符串
System.out.println(sb);// 输出:abc12.3atrue你好
// sb.reverse()与sb的内容一样说明是直接在容器内部反转 而不是将反转的内容存放在新的容器中
System.out.println(sb.reverse());// 输出:好你eurta3.21cba
System.out.println(sb);// 输出:好你eurta3.21cba
}
}
3、StringBuilder容器名.length()
作用:返回长度(字符出现的个数)
public class test2 {
public static void main(String[] args) {
StringBuilder sb=new StringBuilder("abc");
System.out.println(sb.length());// 输出:3
}
}
4、StringBuilder容器名.toString()
作用:通过toString()就可以把StringBuilder转化为String,返回字符串 因为通过StringBuilder拼接后是StringBuilder类型,不是String类型,因此需要转化
public class test2 {
public static void main(String[] args) {
StringBuilder sb=new StringBuilder("文韬");
sb.append("你好");
sb.append("星期六");
System.out.println(sb);// 输出:文韬你好星期六
// 这里的sb不是字符串 而是一个可以操作字符串的容器 因此我们需要将容器转化为字符串
String str=sb.toString();
System.out.println(str);// 输出:文韬你好星期六
// 这里的str是字符串
}
}
3、链式编程
当我们调用一个方法后不用接收它的返回值,而是继续调用方法,通过链式编程思想我们可以简化代码
简化前:
简化后:
4、StringBuilder使用场景
1、字符串的拼接
2、字符串的反转
十一、StringJoiner
StringJoiner和StringBuilder一样是一个容器,创建之后里面的内容是可变的
1、StringJoiner构造方法
空参构造:
public StringJoiner(间隔符号);
创建一个StringJoiner对象,指定拼接时的间隔符号
带参构造:
public StringJoiner(间隔符号,开始符号,结束符号);
创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号、结束符号
注意:间隔符不能以字符的形式输入
因为分隔符(delimiter)、前缀(prefix)、后缀(suffix),它们的类型为 CharSequence,CharSequence
是一个接口,它表示一个字符序列,而 String
类实现了这个接口。char
类型的值需要被包装成 String
才能作为 CharSequence
使用。
2、StringJoiner成员方法
1、StringJoiner容器名.add(添加的内容)
注意:添加的内容主要是字符串
作用:添加数据,并返回对象本身(仍是StringJoiner类型 因此可以使用链式编程的思想添加元素)
2、StringJoiner容器名.length()
作用:返回长度(字符出现的个数,包括间隔符号和开始、结束符号)
3、StringJoiner容器名.toString()
作用:通过toString()就可以把StringJoiner转化为String,返回字符串 因为通过StringJoiner拼接后是StringJoiner类型,不是String类型,因此需要转化
十二、字符串拼接的底层原理
对于不含变量的字符串进行拼接 在编译成字节码文件时就拼接好了 在实际运行的时候就是已经拼接好的字符串
public class StringJoinerdemo2 {
public static void main(String[] args) {
String s1="abc";
// 对于不含变量的字符串进行拼接 在编译成字节码文件时就将"a"+"b"+"c"拼接成"abc"
// 在实际运行的时候s2就是"abc"
String s2="a"+"b"+"c";
System.out.println(s1==s2);
// 输出:true
}
}
JDK8以前,如果有变量参与字符串的拼接,那么就会创建一个StringBuilder容器对象来存放变量的值并进行拼接,最后将StringBuilder容器转化为字符串类型(且这个字符串是在堆中重新生成的字符串),JDK8以后,它会预估拼接好的字符串的长度,并将字符串存放到数组中,此时的字符串也是新的字符串
public class StringJoinerdemo2 {
public static void main(String[] args) {
String s1="abc";// s1是记录串池中的地址值
String s2="ab";
String s3=s2+"c";// s3是新new出来的对象
System.out.println(s1==s3);
// 输出:false
// 如果将String s3=s2+"c";改为String s3="ab"+"c";
// 那么System.out.println(s1==s3);输出结果为true
}
}
十三、StringBuilder源码分析
创建一个StringBuilder就会默认创建一个长度为16的字节数组
添加的内容长度小于16就会直接存放内容
添加的内容长度大于16就会进行扩容(扩容后的容量为原来的容量*2+2 即34)
如果扩容后仍然不够存放添加的内容就以实际长度为准