一、String

1) 分类
不可变的 String
可变的就是 StringBuffer、 StringBuilder
2) 理解
String a = “Hello”
a = “World” 不是将Hello 的值改变为 “World” 而是重新创建了一个”World “ 将地址给了a ;

  1. <br /> ![image.png](https://cdn.nlark.com/yuque/0/2022/png/22131196/1646876806672-18736bde-aa10-4ee8-8932-94d8b8f9ff82.png#clientId=u38369c40-227b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=301&id=uf9074c8e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=602&originWidth=957&originalType=binary&ratio=1&rotation=0&showTitle=false&size=33071&status=done&style=none&taskId=ucb5069e0-2981-4627-91a7-d65c1cdd8b1&title=&width=478.5)<br />3、equals
package com.qfedu.day08_01;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 9:38
 * @Version 1.0
 */
public class Demo01 {

    /**
     *
     *   String 是不可变的字符串
     *   1、理解  "Hello"  这个字符串在jvm中的值是不会改变的
     */
    public static void main(String[] args) {
        String a = "Hello" ;
        // String   a = "Hello"
        // a  = "World"
        // 不是将Hello 的值改变为 “World" 而是重新创建了一个”World "  将地址给了a  ;
        // a = "world" ;

        String b = "Hello" ;
        // 当  a = "Hello" 赋值的时候会先从常量池的查找是否有"Hello" 如果没有,创建”Hello" 字符串
        //  赋值给 a  ,当下一次  b = "Hello"  就从字符串常量池寻找“Hello" 进行赋值,所以
        //  a 和 b 在内存中的地址是一样的
        System.out.println(a==b);
        // "Hello"   "World"
        /**
         *  equals  本身是Object 父类的方法
         *  String 也是Object 的子类
         *  String 重写了 equals
         *  原理是:先判断长度是否相同,长度相同; 将两个字符串全部变为字符数组
         *  char[] arr = {'H','e','l','l','o'}
         *  进行循环比对,只要有一位不一样,直接返回false
         */
        System.out.println(a.equals(b));
    }
}

4、享元原则以及效率对比

package com.qfedu.day08_01;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 9:59
 * @Version 1.0
 */
public class Demo02 {

    /**
     *  字符串的值为什么要放在 常量池 中呢?
     *   享元原则  -->  经常用到的内容 放在一个地方,进行多方面的共享
     */


    public static void main(String[] args) {

        /**
         *   先将数值类型的10  放在一个数组中,下一次又遇到了 10 ,直接取出来
         *   [-128,127)
         */
        Integer i = Integer.valueOf(10);
        Integer i2 = Integer.valueOf(10);
        System.out.println(i == i2);

        Integer i3 = Integer.valueOf(200);
        Integer i4 = Integer.valueOf(200);
        System.out.println(i3 == i4);

        String  a = "bigdata";
        String  b = "bigdata";
        /**
         *  a,b  指向的是常量池中的 “bigdata" 所对应的地址
         */
        String aa = new String("bigdata");
        String bb = new String("bigdata");
        /**
         *   以上代码创建了两个对象   堆  &  常量池中
         *   aa 指向了堆中的一个 实例化对象,实例化中的指针,指向了常量池中的 “bigdata"地址
         *   bb 指向了堆中的一个 实例化对象,实例化中的指针,指向了常量池中的 “bigdata"地址
         */
        System.out.println(aa == bb);

        /**
         *   String  a = "bigdata";
         *   效率要高于
         *   String  a =new String("bigdata");
         */
    }

}

5、字符串拼接

package com.qfedu.day08_01;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 10:15
 * @Version 1.0
 */
public class Demo03 {

    public static void main(String[] args) {
        //  a 指向的是 在常量池中进行拼接以后的第三个字符串 "HelloWorld"
        String a = "Hello" + "World" ;
        String b = new String("Hello");
        String c = new String("World");
        String d = b + c ;//  d 指向的是不是常量池中拼接以后的地址
        //在这个拼接的过程中, 隐式的实例化了一个String类的对象, 在堆上开辟了空间。
        // 堆上空间内部维护了一个指向了常量池中拼接结果的一个属性。 这个堆上的空间地址给左侧的引用进行了赋值
        System.out.println(a == d);

        String e = new String("Hello") + "World" ; // 会产生新的对象的
        System.out.println(e == d); // false
        System.out.println(e == a); // false

    }
}

image.png
6、字符串的构造方法

package com.qfedu.day08_01;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 10:58
 * @Version 1.0
 *
 * String 的构造方法
 */
public class Demo04 {

    public static void main(String[] args) {
        String s = new String(); // String s = "";
        System.out.println(s);
        String s1 = new String("abc"); // String s1 = "abc"
        System.out.println(s1);
        System.out.println(s1.toString());
        char[] sArr = {'H','e','e','A','B'};
        String s2 = new String(sArr);
        System.out.println(s2);
        System.out.println(new String(sArr, 2, 3));
        // 作用不是特别大,了解一下
        byte[] sArr2 ={122,93,89};
        String s3 = new String(sArr2);
        System.out.println(s3);

    }
}

7、常用方法

package com.qfedu.day08_01;

import java.util.Arrays;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 11:14
 * @Version 1.0
 */
public class Demo05 {
    public static void main(String[] args) {
        char[] sArr = {'H','e','e','A','B'};
        System.out.println(new String(sArr));
        String s = "hello" ;
        // 将字符串变为数组
        char[] array = s.toCharArray();
        System.out.println(Arrays.toString(array));
        // 获取字符串中某个位置的字符,从0 开始的
        System.out.println(s.charAt(0));

        // 比较两个字符串(按照字典顺序)
        //  Hello  Hallo
        /**
         *   依次比对各个位数上的字典顺序,如果返回 正数说明前面的大有后面的
         *   小于就是后面的大于前面的,等于0 说明两个字符串相等。
         */
        System.out.println("Hello".compareTo("Hallo"));
        System.out.println("Hello".compareTo("Hello"));
        System.out.println("Hello".equals("Hello"));

        System.out.println("Hello".compareTo("hello"));
        System.out.println("Hello".compareToIgnoreCase("hello"));

        // 字符串拼接
        /**
         *   五种字符串的拼接方式,将来最一个性能分析:
         *
         *   String a = "abc"+"bcd"
         *   String a = new String("abc") + new String("bcd")
         *   String a = "abc".concat("cbd")
         */
        System.out.println("abc".concat("cbd"));

        // public interface CharSequence   String 就是这个接口的实现类
        // 字符串中是否包含另一个字符串
        System.out.println("Hello".contains("o"));// boolean
        //System.out.println("Hello".contains('o'));
        // 字符串中第一次出现另个字符串的下标
        System.out.println("Hello".indexOf("a")); // 返回下标  存在 返回 >= 0 的数 ,不存在,返回 -1
        System.out.println("Hello".indexOf("ll")); // 返回 2


        /**
         *  不重要
         *  将char[] 数组变为  字符串
         */
        System.out.println(String.valueOf(sArr));
        System.out.println(String.copyValueOf(sArr));

        /**
         *   字符串是否以某个字符串结尾
         */
        System.out.println("Hello".endsWith("o"));
        System.out.println("Hello".endsWith("lo"));

        System.out.println("ABC".equals("abc"));
        /**
         *   忽略大小写比较,内容比较
         */
        System.out.println("ABC".equalsIgnoreCase("abc"));

        /**
         *  format
         *    %s --> 字符串
         *    %ns  --> 长度为n的字符串
         *    %d  --> 整数
         *    %nd  --> n位 的整数
         *    %.nf  --> 精确到小数点后n位的小数
         */
        String ss = String.format("姓名是:%s,年龄是%d,考了%.2f分","小明",20,88.5789);
        System.out.println(ss);

        String ss2 = String.format("姓名是:%10s,年龄是%5d,考了%.2f分","小明",20,88.5789);
        System.out.println(ss2);

        // indexOf  第一次出现的下标位置是多少
        /**
         *  如果传递的是一个int类型的参数,先将参数转换为对应的char,再查找
         */
        System.out.println("Hello".indexOf(72));
        System.out.println("Hello".indexOf("o"));
        System.out.println("Hello".indexOf("l")); // 2
        System.out.println("Hello".indexOf("l",3));// 3

        String  str = "";
        System.out.println(str.isEmpty());
        String  str2 = " "; // 长度是1
        System.out.println(str2.isEmpty());
        String str3 = null;
        //  Exception in thread "main" java.lang.NullPointerException
        // 任何一个null 的对象,调用任何方法,都会报  空指针异常
        // 如果出现空指针,定位到代码处,只有两个地方会出现  80% 是前面,20% 是参数
        System.out.println(str3.isEmpty());


    }
}

如何自定义判断一个字符串是否为空 isEmpty()

package com.qfedu.day08_01;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 14:39
 * @Version 1.0
 */
public class StringUtils {

    /**
     *  判断一个字符串是否为空
     */
    public static boolean isEmpty(String str){
        // 先判断是否为null
        if(str != null && !str.equals("") && !str.equals("null")){
            return false;
        }
        return true;
    }

    // 错误演示,一定要先判断是否为null 才行
    /*public static boolean isEmpty(String str){
        // 先判断是否为null
        if( !str.equals("") && !str.equals("null") && str != null ){
            return false;
        }
        return true;
    }*/

    public static void main(String[] args) {
         isEmpty(null);
    }
}
package com.qfedu.day08_01;

import java.util.Arrays;
import java.util.Scanner;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 14:48
 * @Version 1.0
 */
public class Demo06 {

    /**
     *  String 常用方法
     * @param args
     */
    public static void main(String[] args) {
        /*
           将多个字符串拼接为新的字符串,可以指定拼接符
         */
        String message = String.join("~", "Java", "is", "cool");
        System.out.println(message);

        /**
         *   从最后往前看,出现第一次字符串的下标是多少
         *   indexOf 是一样的,只有查找的方向不一样
         */
        System.out.println("Hello".lastIndexOf("l"));// 3

        /**
         *  返回字符串的长度
         */
        System.out.println("Hello".length());
        String[] arr = new String[8];
        System.out.println(arr.length);

        /*Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个数字:");
        int i = scanner.nextInt();
        System.out.println(i);*/
        String a = "Hello World Zhangsan Ni Hao";
        String replaceStr = a.replace(" ", "##");
        System.out.println(replaceStr);
        // 替换所有的符合内容的地方,替换成新的字符串
        System.out.println(a.replaceAll(" ", "**"));

        // 通过某个规则进行切割,切割完之后返回数组
        String[] arrStr = a.split(" ");
        System.out.println(Arrays.toString(arrStr));

        System.out.println("Hello".startsWith("He"));

        /**
         *  subString 截取
         *
         *   从什么位置开始截取(包含)
         *    到什么位置结束 (不包含)
         */
        System.out.println("Hello".substring(1,4));
        // 如果只输入一个值,说明从这个下标开始,截取到最后一个
        System.out.println("Hello".substring(1));

        // 将字符串中的所有字符全部转为小写
        System.out.println("Hello".toLowerCase());
        // 将字符串中的所有字符全部转为大写
        System.out.println("Hello".toUpperCase());
        System.out.println("闫".toLowerCase());// 无变化,原样输出

        /**
         *     "Hello  ".equals("Hello")   false
         */
        System.out.println("Hello    ".trim());
        System.out.println("   Hello  World   ".trim());
        System.out.println("Hello".trim());

        System.out.println(String.valueOf(1));


    }
}

replace 和 replaceAll

       /**
         *   replace(old,new)   是全部替换
         *   replaceAll(正则表达式,new)  是全部替换
         */
        String  ss = "   Hello      World   ";
        System.out.println(ss.replace(" ","*"));
        String regex = "\\s" ; // 匹配 空白(空格\tab)   //

        System.out.println(ss.replaceAll(regex,"#"));
         //System.out.println(ss.replace(regex,"*"));  // 不报错,没作用

二、StringBuffer和StringBuilder类

作用:可变字符串
StringBuffer : 线程安全的,但是效率不及StringBuilder
StringBuilder : 线程不安全的,效率高。
字符串内容拼接效率对比:

效率: 1、字符串通过+ 进行拼接效率非常的慢。
原因是:会在常量池中创建大量的一次性的常量,而且还得回收。
2、StringBuilder 效率要高于 StringBuffer
底层原理: 通过数组进行存储的
1) char[] a = new char[100] ;
append 方法 ,就将这个字符 放入数组中。
2) 如果一旦满了,就自动扩容。创建新的数组,将老的数组的值赋值给新数组,进行在新的数组中存放内容
* 不需要创建大量的对象,效率比较高。

package com.qfedu.day08_01;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 16:10
 * @Version 1.0
 *
 *       效率: 1、字符串通过+ 进行拼接效率非常的慢。
 *             原因是:会在常量池中创建大量的一次性的常量,而且还得回收。
 *             2、StringBuilder 效率要高于 StringBuffer
 *             底层原理:  通过数组进行存储的
 *                 1)  char[] a = new char[100] ;
 *                       append 方法 ,就将这个字符 放入数组中。
 *                 2)  如果一旦满了,就自动扩容。创建新的数组,将老的数组的值赋值给新数组,进行在新的数组中存放内容
 *                      不需要创建大量的对象,效率比较高。
 */
public class Demo08 {

    public static void main(String[] args) {
        long begin = System.currentTimeMillis();
        String a = " ";
        // 执行你像看到的代码
        for (int i = 0; i < 100000; i++) {
             a += i;
        }
        long end  = System.currentTimeMillis();
        System.out.println("通过字符串+J进行运算的执行时间:"+(end-begin));


        long begin2 = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer();
        // 执行你像看到的代码
        for (int i = 0; i < 100000; i++) {
            sb.append(i);
        }
        long end2  = System.currentTimeMillis();
        System.out.println("通过StringBuffer进行运算的执行时间:"+(end2-begin2));


        long begin3 = System.currentTimeMillis();
        StringBuilder sb2 = new StringBuilder();
        // 执行你像看到的代码
        for (int i = 0; i < 100000; i++) {
            sb2.append(i);
        }
        long end3  = System.currentTimeMillis();
        System.out.println("通过StringBuilder进行运算的执行时间:"+(end3-begin3));
    }
}

三、正则表达式

独立的技术: 编写好了一个正则表达式,可以作用与任何的开发语言,不仅仅是java。

元字符 意义
^ 匹配一个字符串的开头。 在Java的正则匹配中,可以省略不写。
$ 匹配一个字符串的结尾。 在Java的正则匹配中,可以省略不写。
[] 匹配一位字符。
[abc]: 表示这一位的字符, 可以是a、也可以是b、也可以是c 。
[a-z]: 表示这一位的字符, 可以是 [a, z] 范围内的任意的字符。
[a-zABC]: 表示这一位的字符, 可以是 [a,z ] 范围内的任意字符, 或者A、或者B、或者C 。
[a-zA-Z]: 表示这一位的字符, 可以是任意的字母, 包括大写字母和小写字母。
[^abc]: 表示这一位的字符, 可以是除了 a、b、c 之外的任意字符。
[^a-z[hk]]: 表示这一位的字符, 不能是任意的小写字母, 但是 h 、 k 除外。
\ 转义字符。 由于正则表达式在Java中是需要写在一个字符串中。 而字符串中的\也是一个转义字符。 因此Java中写正则表达式的时候, 转义字符都是 \\
使得某些特殊字符成为普通字符, 可以进行规则的指定。
使得某些普通字符变得具有特殊含义。
\d 匹配所有的数字, 等同于 [0-9] 。
\D 匹配所有的非数字, 等同于 [^0-9] 。
\w 匹配所有的单词字符, 等同于 [a-zA-Z0-9_] 。
\W 匹配所有的非单词字符, 等同于 [^a-zA-Z0-9_] 。
. 通配符, 可以匹配一个任意的字符。
+ 前面的一位或者一组字符, 连续出现了一次或多次。
? 前面的一位或者一组字符, 连续出现了一次或零次。
* 前面的一位或者一组字符, 连续出现了零次、一次或多次。
{} 对前面的一位或者一组字符出现次数的精准匹配。
{m} : 表示前面的一位或者一组字符连续出现了m次。
{m,} : 表示前面的一位或者一组字符连续出现了至少m次。
{m,n} : 表示前面的一位或者一组字符连续出现了至少m次,最多n次。
| 作用于整体或者是一个分组, 表示匹配的内容, 可以是任意的一个部分。
abc|123|opq : 表示整体的部分, 可以是 abc, 也可以是 123, 也可以是 opq
() 分组。 把某些连续的字符视为一个整体对待。

正则表达式训练:

/**
 * @Author 千锋大数据教学团队
 * @Company 千锋好程序员大数据
 * @Date 2020/4/15
 * @Description 正则表达式的基础语法
 */
public class Regex2 {
    public static void main(String[] args) {
        // 校验规则:
        System.out.println(",ello".matches("[ahj1,8]ello"));
        System.out.println("fello".matches("[a-z]ello"));
        // 需求: 首位字符,可以是任意的小写字母,或者是 HAQ
        System.out.println("Hello".matches("[Ha-zAQ]ello"));
        // 需求: 首位字符,可以是任意的字母,包括大写字母和小写字母
        System.out.println("hello".matches("[a-zA-Z]ello"));
        // 需求: 首位字符,可以是除了h之外的任意字符
        System.out.println("Hello".matches("[^hel]ello"));
        // 需求: 首位字符,不可以是任意的小写字母,但是 h、e、q 除外
        System.out.println("lello".matches("[^a-z[heq]]ello"));

        // 希望首位字符,可以是 h e [
        System.out.println("]ello".matches("[he\\[]ello"));
        // 希望首位字符,可以是 a - z
        System.out.println("hello".matches("[az-]ello"));

        System.out.println("hello".matches("hel+o"));
        System.out.println("hello".matches("hel?o"));
        System.out.println("heo".matches("hel*o"));

        System.out.println("hello".matches("hel{3}o"));
        System.out.println("hello".matches("hel{3,}o"));
        System.out.println("hello".matches("hel{3,5}o"));

        // 需求: 匹配一个字符串可以是 126 或者是 163 或者是 qq 或者是 QQ
        System.out.println("123".matches("126|163|qq|QQ"));
        // 需求: 匹配一个qq邮箱、126邮箱、163邮箱
        System.out.println("admin@sina.com".matches("admin@(qq|126|163)\\.com"));
    }
}

正则表达式实战:

package com.qfedu.day08_01;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 17:36
 * @Version 1.0
 */
public class Demo10 {

    public static void main(String[] args) {

         String  regex = "1[356789][0-9]{9}";
        System.out.println("18638147931".matches(regex));
        System.out.println("1863814793".matches(regex));
        System.out.println("14638147931".matches(regex));
        //  xxxxx@qq.com
        //   ssss@163.com
        //   343434@gmail.com
        //   yanzhenwei@1000phone.net
        String regexEmail = "\\w+@[a-zA-Z0-9]+\\.(com|cn|net)";
        System.out.println("yanzhenwei@1000phone.net".matches(regexEmail));
        System.out.println("2384723432@qq.com".matches(regexEmail));
        System.out.println("2d3re4qw@163.com".matches(regexEmail));
        System.out.println("18137884406@126.net".matches(regexEmail));
        System.out.println("18137884406@126.con".matches(regexEmail));
        System.out.println("YNDJKSJK126.con.com".matches(regexEmail));

    }
}

正则表达式的另一种匹配方式:

package com.qfedu.day08_01;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/10 17:36
 * @Version 1.0
 */
public class Demo11 {

    public static void main(String[] args) {

        String  regex = "1[356789][0-9]{9}";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher("18638147931");
        System.out.println(matcher.matches());

        //以上代码相当于
        System.out.println("18638147931".matches(regex));


    }
}