String类
- String对象用于保存字符串,也就是一组字符序列
 - 字符串常量对象是用双引号括起的字符序列。例:"hello","3.1415926","年后"等。
 - 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。
 - String类较常用的构造器:
 
- String s1=new String();
 - String s2=new String(String original);
 - String s3=new String(char[ ] a);
 - String s4=new String(char[] a,int startIndex,int count)
 
- String 类实现了接口 Serializable 【String 可以串行化:可以在网络中传输 】,也实现 接口Comparable 【String 对象可以比较大小】
 - String 是final类,不能被其他类继承。
 - String 有属性 private final char value[];用于存放字符串内容。
 - 一定注意:value 是一个fianl类型,不可修改(不是字符内容不可修改,是存放地址不可修改)
 

创建String对象的两种方式
- 方式一:直接赋值String s="nihao";
 - 方式二:调用构造器String s=new String("nihao");
 
区别:
- 方式一:先从常量池查看是否有"nihao"的数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址。
 - 方式二:先在堆中创建空间,里面维护了value属性,指向常量池的"nihao"空间。如果常量池中没有"nihao",重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
 

字符串特性
- String是一个final类,代表不可变的字符序列
 - 字符串是不变的。一个字符串对象一旦被分配,其内容是不可变的。
 
package com.study.srv.demo11;
/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/3/10 10:12
 */
public class Demo05 {
    public static void main(String[] args) {
        String a="hello";
        String b="abc";
        String c=a+b;
        String d=a+"abc";
        //底层是StringBuilder sb=new StringBuilder(); sb.append(a);sb.append("abc"); sb是在堆中,并且append是在原来字符串的的基础上追加的。
        //重要规则,String e="hello"+"abc";常量相加,看的是常量池。String d=a+"abc";变量相加,是在堆中。
        String e="hello"+"abc";
        String f="helloabc";
        System.out.println(e==f);//说明 String e="hello"+"abc";会自动优化,等价于String f="helloabc";
        System.out.println(c);
        System.out.println(d);
        System.out.println(c==d);
        System.out.println(c==e);
        System.out.println(d==e);
        System.out.println(d==f);
    }
}String d 创建过程如下:




因此与String e="hello"+"abc";这种常量相加指向常量池的不同
String类的常见方法
方法名  | 说明  | 
equals  | 区分大小写,判断内容是否相等  | 
equalsgnoreCase  | 忽略大小写的判断内容是否相等  | 
length  | 获取字符的个数,字符的长度  | 
indexOf  | 获取字符在字符串中第一次出现的索引,索引从0开始,如果找不到,返回-1  | 
lastIndexOf  | 获取字符在字符串中最后一次出现的索引,索引从0开始,如果找不到,返回-1  | 
substring  | 截取指定范围的子串  | 
trim  | 去前后空格  | 
charAt  | 获取某索引处的字符,注意不能使用Str[index]这种方式  | 
toUpperCase  | 将小写字母转换为大写字母  | 
toLowerCase  | 将大写字母转换为小写字母  | 
concat  | 字符串拼接  | 
replace  | 替换字符串中的字符  | 
spit  | 分割字符串  | 
compareTo  | 比较两个字符串大小,如果前者大,则返回正数;后者大,则返回负数;如果相等,则返回0  | 
toCharArray  | 转换为字符数组  | 
valueOf  | 将其他类型转换为字符串  | 
format  | 格式化字符串  | 
String.valueOf()方法
由基本数据型态转换成String:
- String.valueOf(boolean b) : 将 boolean 变量 b 转换成字符串
 - String.valueOf(char c) : 将 char 变量 c 转换成字符串
 - String.valueOf(char[] data) : 将 char 数组 data 转换成字符串
 - String.valueOf(char[] data, int offset, int count) : 将 char 数组 data 中 由 data[offset] 开始取 count 个元素 转换成字符串
 - String.valueOf(double d) : 将 double 变量 d 转换成字符串
 - String.valueOf(float f) : 将 float 变量 f 转换成字符串
 - String.valueOf(int i) : 将 int 变量 i 转换成字符串
 - String.valueOf(long l) : 将 long 变量 l 转换成字符串
 - String.valueOf(Object obj) : 将 obj 对象转换成 字符串, 等于 obj.toString()
 
由 String 转换成 数字的基本数据型态 :
要将 String 转换成基本数据型态转 ,大多需要使用基本数据型态的包装类别 。
- byte : Byte.parseByte(String s) : 将 s 转换成 byte类型。
 - Byte.parseByte(String s, int radix) : 以 radix是进制数 将 s 转换为 byte ,比如说 Byte.parseByte("11", 16) 就代表是16进制的"11",也就是17。
 - double : Double.parseDouble(String s) : 将 s 转换成 double 。
 - float : Double.parseFloat(String s) : 将 s 转换成 float 。
 - int : Integer.parseInt(String s) : 将 s 转换成 int 。
 - long : Long.parseLong(String s)。
 
StringBuffer类
- java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。
 - 很多方法与Sting相同,但StringBuffer是可变长度。
 - StringBuffer是一个容器。
 

package com.study.srv.demo11;
/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/3/11 11:52
 */
public class Demo09 {
    public static void main(String[] args) {
        //1.StringBuffer的直接父类就是 AbstractStringBuilder
        //2.它也实现了java.io.Serializable接口 即StringBuffer的对象可以串行化
        //3.在父类中 有属性char[] value;不是final类型,该value数组存放字符串内容
        //4.StringBuffer是一个final类不能被继承。
        StringBuffer stringBuffer = new StringBuffer();
    }
}String VS StringBuffer
- String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低 //private final char value[];
 - StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用更新地址,效率较高// char[] value;
 
StringBuffer stringBuffer =new StringBuffer();
默认创建一个大小为16的char[],用于存放字符内容。实际上真正存放在父类的value里。


StringBuffer stringBuffer =new StringBuffe(100);
通过构造器指定char[]大小。

StringBuffer stringBuffer = new StringBuffer("hello");

StringBuffer转换
package com.study.srv.demo11;
/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/3/11 16:01
 */
public class Demo10 {
    public static void main(String[] args) {
        //String 转换为StringBuffer
        String str="hello world";
        //方式一:使用构造器
        //注意:返回的是StringBuffer对象,对str本身没有影响。
        StringBuffer stringBuffer = new StringBuffer(str);
        //方式二:使用的是append方法
        StringBuffer stringBuffer1 = new StringBuffer();
        stringBuffer1 = stringBuffer1.append(str);
        //StringBuffer转为String
        StringBuffer stringBuffer2 = new StringBuffer("jack");
        //方式一:使用StringBuffer提供的toString方法
        String s=stringBuffer2.toString();
        System.out.println(s);
        //方式二:使用构造器搞定
        String s1 = new String(stringBuffer2);
        System.out.println(s1);
    }
}StringBuffer常用方法
方法名  | 说明  | 
append  | 增加  | 
delete(start,end)  | 删除  | 
replace(start,end,string)  | 将start--end间的内容替换掉,不含end  | 
reverse()  | 字符串翻转  | 
indexOf  | 查找子串在字符串第一次出现的索引,如果找不到返回-1  | 
insert  | 插入  | 
length  | 获取长度  | 
package com.study.srv.demo11;
/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/3/11 17:01
 */
public class Demo11 {
    public static void main(String[] args) {
        StringBuffer s = new StringBuffer("hello");
        //增加
        s.append(',');//"hello,"
        s.append("java");//"hello,java"
        s.append("app").append(100).append(true).append(3.14);//"hello,javaapp100true3.14"
        System.out.println(s);
        //删除
        /**
         * 删除索引为>=start&&<end处的字符
         */
        s.delete(5,9);//[5,9) 即删除5~9(不包含9)的索引下的字符
        System.out.println(s);
        //修改
        s.replace(0,5,"world");
        System.out.println(s);
        //查找🔍
        //查找指定的字串在字符串第一次出现的索引,如果找不到,返回-1
        int index=s.indexOf("a");
        System.out.println(index);
        //插入
        s.insert(5,"武当张三丰太极剑法");//即在索引为5的地址插入"武当张三丰太极剑法"
        System.out.println(s);
        //长度
        System.out.println(s.length());
        System.out.println(s);
    }
}StringBuilder类
- 一个可变的字符序列。此类提供了一个与StringBuffer兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作StringBuffer的简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer快。
 - 在StringBuffer上的主要操作类型是append和insert方法,可以重载这些方法,以接受任意类型的数据。
 

package com.study.srv.demo11;
/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/3/14 11:04
 */
public class Demo14 {
    public static void main(String[] args) {
        //1.StringBuilder继承了AbstractStringBuilder类
        //2.实现了Serializable,说明StringBuilder对象也是可以串行化的(串行化即是:对象可以用于网络传输,也可以保存到文件中)
        //3.StringBuilder是final类,不能被继承
        //4.StringBuilder对象字符序列仍然存放在其父类AbstractStringBuilder的char[]value;
        //因此,字符序列是存放到堆中
        //5.StringBuilder的方法,没有做同步处理,即没有synchronized 关键字,因此在单线程的情况下使用。所以才会线程不安全。
        StringBuilder stringBuilder = new StringBuilder();
    }
}为什么StringBuffer是线程安全的,而StringBuilder是线程不安全的?原因就在于synchronized关键字。
@Overridepublic synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this;}
@Overridepublic StringBuilder append(String str) { super.append(str); return this;}
StringBuilder在append操作时并未使用线程同步,而StringBuffer几乎大部分方法都使用了synchronized关键字进行方法级别的同步处理。
String、StringBuffer和StringBuilder比较
- StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也一样。
 - String:不可变字符序列,效率低,但是复用率低。
 - StringBuffer:可变字符序列,效率高(增删)、线程安全。
 - StringBuilder:可变字符序列,效率最高,但是线程不安全。
 
String使用注意说明:
String s="a"; //创建了一个字符串
s+="b";//实际上原来的"a"字符串对象已经丢弃了,现在又产生一个字符串"ab"。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大的影响程序的性能。所以,如果我们对String做大量的修改,不要使用String一般使用StringBuffer,如果是单线程的话使用StringBuilder。
package com.study.srv.demo11;
/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/3/14 11:53
 */
public class Demo15 {
    public static void main(String[] args) {
        String s="";
        long startDate=0;
        long endDate=0;
        StringBuffer sb = new StringBuffer();
        StringBuilder sd = new StringBuilder();
        startDate=System.currentTimeMillis();
        for (int i=0;i<50000;i++){
            s+=i;//String拼接
        }
        endDate=System.currentTimeMillis();
        System.out.println("String执行时间为:"+(endDate-startDate));
        startDate=System.currentTimeMillis();
        for (int i=0;i<50000;i++){
            sb.append(String.valueOf(i));//StringBuffer拼接
        }
        endDate=System.currentTimeMillis();
        System.out.println("StringBuffer执行时间为:"+(endDate-startDate));
        startDate=System.currentTimeMillis();
        for (int i=0;i<50000;i++){
            sd.append(String.valueOf(i));//StringBuilder拼接
        }
        endDate=System.currentTimeMillis();
        System.out.println("StringBuilder执行时间为:"+(endDate-startDate));
    }
}String、StringBuffer、StringBuilder的选择
使用原则,结论:
- 如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder。
 - 如果字符串存在大量的修改操作,并且在单线程情况下,使用StringBuilder。
 - 如果字符串存在大量的修改操作,并且在多线程情况下,使用StringBuffer。
 - 如果字符串很少修改,被多个对象引用,使用String。
 










