一、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)
如果扩容后仍然不够存放添加的内容就以实际长度为准

















