跳至主要內容

11. String

景天大约 21 分钟

String概述

基本介绍

基本介绍

  • 一个字符串是由多个字符组成的一串数据(字符序列,字符数组)
  • String类代表字符串,Java 程序中的所有字符串字面值(如 "abc" ,"你好","の")都作为此类的实例实现
  • 在java.lang包下,是java核心类,最常用类,但是不属于基本数据类型,引用类型
  • String类提供了字符串表示、比较、查找、截取、大小写转换等各种针对字符串的操作

构造方法

  • 空字符串""
  • byte[] -----> String
  • char[] -----> String
  //空字符串 ""  
  public String()  

  //利用字节数组,创建字节数组所表示的字符串
  // 1. 字符 -> 数值形式  'a' -> 97
  // 2. 所以可以用多个字节值,表示多个字符——>即字符序列 public
  String(byte[] bytes)

  //利用字节数数组的一部分,创建字符序列, 从byte数组的offset开始的length个字节值
  public String(byte[] bytes,int offset,int length)

  //利用一个字符数组创建字符数组,代表的字符序列
  public String(char[] value)

  // 创建value字符数组中,从第offset位置开始的count个字符,所代表的字符串对象
  public String(char[] value,int offset,int count)
    
  //知道即可
  public String(String original)  

Demo

package _14string.com.cskaoyan._01introduction;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/11 10:25
 **/
/*
String 构造方法
 */
public class Demo {
    public static void main(String[] args) {
        //   //空字符串 ""
        //  public String()
        String s = new String();
        System.out.println("s = " + s);
        //  //利用字节数组,创建字节数组所表示的字符串
        //  // 1. 字符 -> 数值形式  'a' -> 97
        //  // 2. 所以可以用多个字节值,表示多个字符——>即字符序列 public
        //  String(byte[] bytes)
        byte[] bytes = {97, 98, 99, 100};
        String s1 = new String(bytes);
        System.out.println("s1 = " + s1);

        //  //利用字节数数组的一部分,创建字符序列, 从byte数组的offset开始的length个字节值
        //  public String(byte[] bytes,int offset,int length)
        String s2 = new String(bytes,0,2);
        System.out.println("s2 = " + s2);
        //  //利用一个字符数组创建字符数组,代表的字符序列
        //  public String(char[] value)
        char[] chars = {'h', 'e', 'l', 'l', 'o'};
        String s3 = new String(chars);
        System.out.println("s3 = " + s3);

        //  // 创建value字符数组中,从第offset位置开始的count个字符,所代表的字符串对象
        //  public String(char[] value,int offset,int count)
        //
        //  //知道即可
        //  public String(String original)
        String zs = new String("zs");
        System.out.println("zs = " + zs);

    }
}

String特点(重点)

String对象不可变

对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化。

1.请键盘录入一个任意字符串s,并用一个temp字符串引用也指向它 这个时候修改temp字符串的内容,请问s字符串的内容会随之改变吗?

package _14string.com.cskaoyan._02feature;

import java.util.Scanner;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 11:50
 **/
/*
请键盘录入一个任意字符串s,并用一个temp字符串引用也指向它
这个时候修改temp字符串的内容,请问s字符串的内容会随之改变吗?
 */
public class Demo {
    public static void main(String[] args) {
        // 创建Scanner对象
        Scanner scanner = new Scanner(System.in);
        // 键盘接收nextLine   -- > s
        String s = scanner.nextLine();
        // temp 指向
        String temp = s;
        // 更改s内容
        s = "aaa";
        // 打印
        System.out.println("temp = " + temp);
        System.out.println("s = " + s);

    }
}

image-20221013142443901
image-20221013142443901

2

String s = "张三";
System.out.println("s = " + s);
s = "hello 张三";
System.out.println("s = " + s);

输出结果是多少?原因是什么?

image-20221013142833360
image-20221013142833360

原因与本质

  • String是一个final类,不能被继承, 代表不可变的字符序列
  • 字符串是常量,用双引号引起来,他们的值在创建之后不可更改
  • String对象的内容是存储在字符数组value[ ]中的
image-20221013143119029
image-20221013143119029
image-20221013143304118
image-20221013143304118
image-20221013143557858
image-20221013143557858

字符串常量池

字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串使用的非常多

JVM为了提高性能和减少内存的开销,在实例化字符串对象的时候进行了一些优化:

使用字符串常量池。

首先要明确,Java的双引号引起来的字面值常量字符串,它们都是对象。这些对象比较特殊,程序在编译时期就能确定它们的值

每当创建字符串常量对象时,JVM会首先检查字符串常量池,如果该字符串对象引用已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串对象引用不存在于常量池中,就会实例化该字符串并且将其引用放到常量池中。

// 当常量池中已有字符串对象的引用时,不会在堆上再创建, 而使用同一引用
String s1 = "abc";
String s2 = "abc";
image-20230407081651412
image-20230407081651412

String两种实例化方式

两种方式

  • 直接赋值 String s = "abc"
  • 构造方法 String s = new String("abc")

第一种 先直接赋值 再构造

String s = "abc";
String s1 = new String("abc")
image-20221013145230940
image-20221013145230940

第二种 先构造 再直接赋值

String s1 = new String("abc")
String s = "abc";
image-20230407081513361
image-20230407081513361

总结:

  • 先String s = new String("abc"), 再String s1 = "abc". new String 的时候会创建2个对象, 直接赋值的时候, 直接用的是常量池的引用, 不再创建新的字符串对象了
  • String s1 = "abc", 再String s = new String("abc"), 直接赋值的方式会创建一个对象, new String的时候会创建1个对象

字符串常见问题与练习

字符串比较

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));

String s3 = new String("hello");
String s4 = "hello";
System.out.println(s3 == s4);
System.out.println(s3.equals(s4));

String s5 = "hello";
String s6 = "hello";
System.out.println(s5 == s6);
System.out.println(s5.equals(s6))

==与equals方法有什么区别?

  • == ,对于基本数据类型而言,比较的是内容,对于引用数据类型而言,比较的是引用变量,即所指向的地址
  • equals方法是Object的方法,默认是比较2个对象的地址,若要比较内容,应当重写父类方法

String中重写的equals方法

image-20221013151301923
image-20221013151301923

字符串拼接

String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hel" + "lo";
String s4 = "Hel" + new String("lo");
String s5 = new String("Hello");
String s7 = "H";
String s8 = "ello";
String s9 = s7 + s8;
          
System.out.println(s1 == s2);// true
System.out.println(s1 == s3);// ?
System.out.println(s1 == s4);// false
System.out.println(s1 == s9);// false
System.out.println(s4 == s5);// false

image-20221013152427336
image-20221013152427336

进行字符串拼接的时候有2种情况

  • 当参与字符串拼接对的2个字符串,只要有1个引用变量的形式出现时,则会在堆上创建新的字符串对象.
    • 原因是因为参与了运算,无法在编译期确定其值,就不能在编译时期加入常量池
  • 只有参与字符串拼接的2个字符串都是字面值常量的时候
    • 如果常量池中已有该字符串对象的引用,则返回常量池中的引用
    • 如果常量池中没有,则在堆上创建,并把引用放入常量池

String API

判断功能

用来比较字符串的内容,注意区分大小写
boolean equals(Object obj)
    
忽略字符串大小写比较字符串内容,常见用于比较网址URL
boolean equalsIgnoreCase(String str)
    
判断当前字符串对象是否包含,目标字符串的字符序列 
boolean contains(String str)
    
判断当前字符串对象,是否已目标字符串的字符序列开头
boolean startsWith(String str)
    
判断当前字符串,是否以目标字符串对象的字符序列结尾,常用于确定文件后缀名格式
boolean endsWith(String str)
    
判断一个字符串,是不是空字符串 
boolean isEmpty()

获取功能

获取当前字符串对象中,包含的字符个数 "abcd"
int length()  
    
获取字符串对象代表字符序列中,指定位置的字符 从0开始"abcd"
char charAt(int index) 
    
在当前字符串对象中查找指定的字符,如果找到就返回字符,首次出现的位置,如果没找到返回-1
也可以填字符   "abcdb"
int indexOf(int ch) 
    
指定从当前字符串对象的指定位置开始,查找首次出现的指定字符的位置,(如果没找到返回-1)
可以填入字符
int indexOf(int ch,int fromIndex) 
    
查找当前字符串中,目标字符串首次出现的位置(如果包含),找不到,返回-1
这里的位置是指目标字符串的第一个字符,在当前字符串对象中的位置  "abcdefg"
int indexOf(String str) 

指定,从当前字符串对象的指定位置开始,查找首次出现的指定字符串的位置(如果没找到返回-1)
这里的位置是指目标字符串的第一个字符,在当前字符串对象中的位置
int indexOf(String str,int fromIndex) ,

返回字符串,该字符串只包含当前字符串中,从指定位置开始(包含指定位置字符)到结束的那部分字符串  "abcdef"
String substring(int start)   
    
返回字符串,只包含当前字符串中,从start位置开始(包含),到end(不包含)指定的位置的字符串  [ , )
String substring(int start,int end) 



Demo

package _14string.com.cskaoyan._03api;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 15:58
 **/
/*
获取功能
 */
public class Demo2 {
    public static void main(String[] args) {
        String s = "abcdef";
        // 获取当前字符串对象中,包含的字符个数 "abcd"
        //int length()
        //
        //获取字符串对象代表字符序列中,指定位置的字符"abcd" 从0开始
        //char charAt(int index)
        System.out.println("s.charAt(0) = " + s.charAt(0));
        //在当前字符串对象中查找指定的字符,如果找到就返回字符,首次出现的位置,如果没找到返回-1
        //也可以填字符   "abcd"
        //int indexOf(int ch)
        //
        //指定从当前字符串对象的指定位置开始,查找首次出现的指定字符的位置,(如果没找到返回-1)
        //可以填入字符
        //int indexOf(int ch,int fromIndex)
        //
        //查找当前字符串中,目标字符串首次出现的位置(如果包含),找不到,返回-1
        //这里的位置是指目标字符串的第一个字符,在当前字符串对象中的位置  "abcd"
        //int indexOf(String str)
        System.out.println("s.indexOf(\"ef\") = " + s.indexOf("ef"));

        //指定,从当前字符串对象的指定位置开始,查找首次出现的指定字符串的位置(如果没找到返回-1)
        //这里的位置是指目标字符串的第一个字符,在当前字符串对象中的位置
        //int indexOf(String str,int fromIndex) ,
        //
        //返回字符串,该字符串只包含当前字符串中,从指定位置开始(包含指定位置字符)到结束的那部分字符串  "abcdef"
        //String substring(int start)
        System.out.println("s.substring(1) = " + s.substring(1));

        //返回字符串,只包含当前字符串中,从start位置开始(包含),到end(不包含)指定的位置的字符串  [ , )
        //String substring(int start,int end)
        System.out.println("s.substring(1, 3) = " + s.substring(1, 3));
    }
}

课堂练习:

1. 统计”abc”在字符中”abcdabcfgh”出现的次数
2. 借助于int indexOf(String str,int fromIndex)
package _14string.com.cskaoyan._03api;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 16:02
 **/

/*
课堂练习:

 	1. 统计”abc”在字符中”abcdabcfgh”出现的次数
	2. 借助于int indexOf(String str,int fromIndex)
 */
public class Ex1 {
    public static void main(String[] args) {
        // 定义字符串
        String s = "abcdabcfgh";
        // 定义计数器
        int count = 0;
        // 定义索引值
        int fromIndex = 0;

        // 循环
        while ((fromIndex = s.indexOf("abc", fromIndex)) != -1) {
            // 计数器 索引值+1
            count++;
            fromIndex++;
        }

        // 循环结束 统计结束 打印
        System.out.println("出现了" + count + "次");
    }
}

课堂练习: 1:遍历获取字符串中的每一个字符 "abc001DEF" 2:统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数。(不考虑其他字符)

package _14string.com.cskaoyan._03api;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 16:10
 **/
/*


课堂练习:
	1:遍历获取字符串中的每一个字符
	"abc001DEF"
	2:统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数。(不考虑其他字符)
 */
public class Ex2 {
    public static void main(String[] args) {
        // 定义字符串
        String s = "abc001DEF";
        // 定义3个计数器
        // digitalCount
        int digitalCount = 0;

        // upperCount
        int upperCount = 0;

        // lowerCount
        int lowerCount = 0;

        // 循环
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            // a-z 小写 A-Z 大写 0-9数字
            // 计数器+1
            if (c >= 'a' && c <= 'z') {
                lowerCount++;
            }
            else if (c >= 'A' && c <= 'Z') {
                upperCount++;
            }else {
                digitalCount++;
            }
        }

        // 循环结束
        // 输出结果
        System.out.println("数字:"+digitalCount);
        System.out.println("大写:"+upperCount);
        System.out.println("小写:"+lowerCount);

    }
}

转换功能

获取一个用来表示字符串对象字符序列的,字节数组
byte[] getBytes()
    
获取的是用来表示字符串对象字符序列的,字符数组
char[] toCharArray() 

    
把字符数组转换成字符串
static String valueOf(char[] chs)

把各种基本数据类型和对象转换成字符串  100---> "100"
static String valueOf(int i/double...)


把字符串全部转化为小写
String toLowerCase() 
    
把字符串全部转换为大写
String toUpperCase()

字符串拼接,作用等价于 + 实现的字符串拼接
String concat(String str) 

package _14string.com.cskaoyan._03api;

import java.util.Arrays;

/**
 * @description: 转换功能
 * @author: 景天
 * @date: 2022/10/13 16:18
 **/
/*
转换功能
 */
public class Demo3 {
    public static void main(String[] args) {
        String s = "abcd";
        // 获取一个用来表示字符串对象字符序列的,字节数组
        //byte[] getBytes()
        byte[] bytes = s.getBytes();
        System.out.println(Arrays.toString(bytes));
        //获取的是用来表示字符串对象字符序列的,字符数组
        //char[] toCharArray()
        char[] chars = s.toCharArray();
        System.out.println(Arrays.toString(chars));

        //把字符数组转换成字符串
        //static String valueOf(char[] chs)
        //
        //把各种基本数据类型和对象转换成字符串  100---> "100"
        //static String valueOf(int i/double...)
        String s1 = String.valueOf(100);
        System.out.println("s1 = " + s1);
        String s2 = String.valueOf(true);
        System.out.println("s2 = " + s2);

        //把字符串全部转化为小写
        //String toLowerCase()
        //
        //把字符串全部转换为大写
        //String toUpperCase()
        String s3 = s.toUpperCase();
        System.out.println("s3 = " + s3);

        //字符串拼接,作用等价于 + 实现的字符串拼接
        //String concat(String str)
        String s4 = s.concat("ef");
        System.out.println("s4 = " + s4);
    }
}

课堂练习: 1:字符串helloWORLD 2:第一个字符转为大写,其余字符转为小写 → Helloworld

package _14string.com.cskaoyan._03api;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 16:25
 **/

/*
课堂练习:
	1:字符串helloWORLD
	2:第一个字符转为大写,其余字符转为小写     →   Helloworld
 */
public class Ex3 {
    public static void main(String[] args) {
        // 定义字符串
        String s = "helloWORLD";

        //func(s);

        String str = s.substring(0, 1).toUpperCase().
                concat(s.substring(1).toLowerCase());
        System.out.println(str);


    }

    private static void func(String s) {
        // 第一个字符取出来 转换大写
        String head = s.substring(0, 1);
        String headStr = head.toUpperCase();

        // 把剩余的字符串取出来 转为小写的
        String remind = s.substring(1);
        String remindStr = remind.toLowerCase();

        // 把转换后的2部分进行拼接
        String newStr = headStr + remindStr;
        System.out.println(newStr);
    }
}

课堂练习: 1:字符串反转 2:举例: 键盘输入abc,反转后结果为cba

package _14string.com.cskaoyan._03api;

import java.util.Scanner;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 16:32
 **/
/*

课堂练习:
	1:字符串反转
	2:举例:
	键盘输入abc,反转后结果为cba
 */
public class Ex4 {
    public static void main(String[] args) {
        // 键盘接收数据abc
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        // 字符串--->char[]  转为字符数组
        char[] chars = s.toCharArray();
        // 定义空字符串
        String str = "";
        // 倒着遍历字符数组
        for (int i = chars.length -1 ; i >= 0 ; i--) {
            // 重写拼接
            str += chars[i];
        }

        // 输出结果
        System.out.println(str);


    }
}

其他功能

String类的替换功能
在新的字符串中,用新(new)字符,替换旧(old)字符  "abcd" 
String replace(char old,char new)  

在新的字符串中,用新的字符串(new), 替换旧(old)字符串
String replace(String old, String new) 


在新的字符串中,去掉开头和结尾的空格字符 "abc"  "abc "
String trim()

分隔功能
将字符串按照符号分隔成字符串数组  "a,b,c,d"
String[] split(String re) 

String类的比较功能
int compareTo(String str)
int compareToIgnoreCase(String str)




课堂练习: 1:给出一句英文句子: "i want a bing dun dun" 2:每个单词的首字母都转换为大写并输出 3.使用split方法

package _14string.com.cskaoyan._03api;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 17:21
 **/
/*
课堂练习:
	1:给出一句英文句子: "i want a bing dun dun"
	2:每个单词的首字母都转换为大写并输出
	3.使用split方法

 */
public class Ex5 {
    public static void main(String[] args) {
        // 定义字符串
        String s = "i want a bing dun dun";
        // 按照空格进行分割 ---> String[]
        String[] strings = s.split(" ");
        // 定义空字符串用于拼接
        String newStr = "";
        // 遍历字符串数组
        for (String str : strings) {
            // 首字母大写准换
            String s1 = str.substring(0, 1).toUpperCase().concat(str.substring(1));
            // 重写拼接
            newStr += s1 + " ";
        }

        // 输出结果
        System.out.println("result:"+newStr.trim());
    }
}

字符串的大小如何比较? 按照字典序,比较字符串的大小。字典序原本的含义实质,英文单词在字典中出现的先后顺序 (在字典中,先出现的字符串小,后出现的字符串大).compareTo方法就是按照字典序进行比较的.

关于compareTo方法

  1. 字符串长度一样,逐一比较返回第一个不一样字符的编码值的差值(调用者-参数)
  2. 字符串长度不一样,并且前面的字符都相同,返回数组长度的差值(调用者-参数)
  3. 长度一样,逐位字符也一样,返回0,表示相等
image-20221013172005780
image-20221013172005780

自然排序

课堂练习: 1:字符串bdcaegf 2:对字符串中的字符进行排序,最终得到结果 → abcdefg

package _14string.com.cskaoyan._04sort;

import java.util.Arrays;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 17:27
 **/
/*
课堂练习:
	1:字符串bdcaegf
	2:对字符串中的字符进行排序,最终得到结果 →  abcdefg

 */
public class Ex {
    public static void main(String[] args) {
        // 定义字符串
        String s = "bdcaegf";

        // 字符串--->char[]
        char[] chars = s.toCharArray();

        System.out.println("排序前");
        System.out.println(Arrays.toString(chars));
        // 排序算法
        // bubbleSort(chars);

        // 简单方法
        Arrays.sort(chars);

        // 输出结果
        System.out.println("排序后");
        System.out.println(Arrays.toString(chars));
    }

    private static void bubbleSort(char[] chars) {
        // 冒泡排序 两两交换 大的放后面
        for (int i = 0; i < chars.length - 1; i++) {
            for (int j = 0; j < chars.length - 1 - i; j++) {
                // 进行交换 大的放后面
                if (chars[j] > chars[j + 1]) {
                    // 定义临时变量接收
                    char temp = chars[j];
                    chars[j] = chars[j+1];
                    chars[j+1] = temp;
                }
            }
        }
    }
}

Comparable接口

此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法

实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序

  • 实现此接口的类,其对象数组(array)或对象容器(collection)
    • 就可以通过**Arrays.sort()Collections.sort()**进行自动排序
  • 对于实现该接口的A类来说,其对象a1.compareTo(a2)方法返回值
    • 小于0,表示a1对象小于a2,在自然排序中处于前面的位置
    • 大于0,表示a1对象大于a2,在自然排序中处于后面的位置
    • 等于0,表示a1对象等于a2

自定义类实现自然排序:

  • 实现Comparable接口
  • 重写compareTo方法

练习: 定义一个学生类,让其按照学生的年龄的大小,从小到大进行排序

package _14string.com.cskaoyan._04sort;

import java.util.Arrays;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 17:44
 **/

public class ComparableTest {
    public static void main(String[] args) {
        // 创建学生对象
        Student s1 = new Student("zs", 22, 77);
        Student s2 = new Student("ls", 21, 88);
        Student s3 = new Student("ww", 25, 66);
        Student s4 = new Student("zl", 22, 99);
        Student s5 = new Student("长风", 26, 59);
        // 填充数组
        Student[] students = {s1, s2, s3, s4, s5};
        // 排序前
        System.out.println("排序前");
        System.out.println(Arrays.toString(students));
        // 排序 sort方法
        Arrays.sort(students);
        // 排序后
        System.out.println("排序后");
        System.out.println(Arrays.toString(students));
    }
}
/*
自定义类实现自然排序:

- 实现Comparable接口
- 重写compareTo方法
 */
class Student implements Comparable<Student>{
    String name;
    int age;
    int score;

    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public int getScore() {
        return score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        // 排序规则
        // 按照年龄从小到大进行排序
        // 按照年龄从大到小进行排序
        //return this.getAge()-o.getAge();
        // 年龄相同的情况下,按照分数从高到低排序
        if (this.getAge() == o.getAge()) {
            return o.getScore() - this.getScore();
        }

        return this.getAge()-o.getAge();
    }

    //@Override
    //public int compareTo(Object o) {
    //    return 0;
    //}
}

Comparator接口

在排序时需要注意一个比较特殊的方法,带比较器的Arrays.sort方法, 即sort(T[] a, Comparator<? super T> c) 根据指定比较器产生的顺序对指定对象数组进行排序。其中Comparator接口的实现类对象就是比较器,该对象通过compare方法传入比较的规则

表示传入比较规则的int compare(T o1, T o2)方法: 该方法可以看成是o1-o2,如果方法返回负数,o1< o2,相反则大于,只有当方法返回0时,才表示对象相等

三种方式去实现自然排序:

  • 手写接口类实现
  • 匿名内部类
  • lambda表达式
package _14string.com.cskaoyan._04sort;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/13 17:44
 **/

public class ComparatorTest {
    public static void main(String[] args) {
        // 创建学生对象
        Student2 s1 = new Student2("zs", 22, 77);
        Student2 s2 = new Student2("ls", 21, 88);
        Student2 s3 = new Student2("ww", 25, 66);
        Student2 s4 = new Student2("zl", 22, 99);
        Student2 s5 = new Student2("长风", 26, 59);
        // 填充数组
        Student2[] students = {s1, s2, s3, s4, s5};
        // 排序前
        System.out.println("排序前");
        System.out.println(Arrays.toString(students));
        // 排序 使用带比较器的sort方法
        //Arrays.sort(students, new MyComparator());

        // 使用匿名内部类
        Arrays.sort(students, new Comparator<Student2>() {
            @Override
            public int compare(Student2 o1, Student2 o2) {
                return o1.getScore() - o2.getScore();
            }
        });

        // 使用lambda
        Arrays.sort(students, (stu1, stu2) -> stu2.getScore() - stu1.getScore());

        // 排序后
        System.out.println("排序后");
        System.out.println(Arrays.toString(students));
    }
}


class Student2{
    String name;
    int age;
    int score;

    public Student2(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public int getScore() {
        return score;
    }

    @Override
    public String toString() {
        return "Student2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

}

// 手写实现类
class MyComparator implements Comparator<Student2> {

    @Override
    public int compare(Student2 o1, Student2 o2) {
        // 按照年龄从小到大进行排序
        //return o1.getAge() - o2.getAge();
        return o2.getAge() - o1.getAge();
    }
}

可变长字符串

如果一个空字符串””,让其拼接10000次,效率怎么样? 我们如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。

package _14string.com.cskaoyan._05stringbuffer;

/**
 * @description:
 * @author: 景天
 * @date: 2022/10/14 9:47
 **/
/*
如果一个空字符串””,让其拼接10000次,效率怎么样?
我们如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。

 */
public class Demo {
    public static void main(String[] args) {
        String str = "";

        StringBuffer sb = new StringBuffer();
        // 获取当前时间戳
        long start = System.currentTimeMillis();
        //int sum = 0;
        for (int i = 0; i < 1000000; i++) {
            //str += "a";
           // sum+=i;
            sb.append("a");
        }
        long end = System.currentTimeMillis();
        // 7s
        // 4ms
        System.out.println(end - start);
    }
}

StringBuffer构造方法

public StringBuffer() // 默认容量是16
public StringBuffer(int capacity)// 容量是capacity
public StringBuffer(String str)// str的长度+16

StringBuffer成员方法

获取功能
public int capacity() 返回当前容量,数组的长度,理论值
public int length() 返回长度(字符的个数),实际值    
添加功能
public StringBuffer append(String s) 将指定的字符串(其他类型有重载方法)追加到此字符序列的尾部
在指定位置把任意类型的数据插入到字符串缓冲区里面
public StringBuffer insert(int offset,String str) 
删除功能
public StringBuffer deleteCharAt(int index):删除指定位置的字符
public StringBuffer delete(int start,int end):删除从指定位置开始指定位置结束的内容
替换功能
使用给定String中的字符替换词序列的子字符串中的字符
public StringBuffer replace(int start,int end,String str)
反转功能
public StringBuffer reverse():将此字符序列用其反转形式取代,返回对象本身


    @Test
    public void apiTest() {
        // 获取功能
        //public int capacity() 返回当前容量,数组的长度,理论值
        //public int length() 返回长度(字符的个数),实际值
        //添加功能
        //public StringBuffer append(String s) 将指定的字符串(其他类型有重载方法)追加到此字符序列的尾部
        //在指定位置把任意类型的数据插入到字符串缓冲区里面
        StringBuffer sb = new StringBuffer();
        sb.append("abc");
        System.out.println("sb = " + sb);
        sb.append("def");
        System.out.println("sb = " + sb);

        //public StringBuffer insert(int offset,String str)
        //删除功能
        //public StringBuffer deleteCharAt(int index):删除指定位置的字符
        //public StringBuffer delete(int start,int end):删除从指定位置开始指定位置结束的内容
        //替换功能
        //使用给定String中的字符替换词序列的子字符串中的字符
        //public StringBuffer replace(int start,int end,String str)
        //反转功能
        //public StringBuffer reverse():将此字符序列用其反转形式取代,返回对象本身
        System.out.println("sb.reverse() = " + sb.reverse());

    }

常见问题

String, StringBuffer之间的相互转换

    @Test
    public void transfer() {
        // String---->StringBuffer
        String s = "abc";
        StringBuffer sb = new StringBuffer(s);
        System.out.println(sb.reverse());

        // StringBuffer---->String
        String s1 = sb.toString();
        System.out.println(s1);
    }

String, StringBuffer和StringBuilder有啥区别

StringBuffer和StringBuilder从效率上来说哪个更快?

image-20221014102227298
image-20221014102227298
  • 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改
    • 并且不产生新的未使用对象,不会产生效率问题和空间浪费问题
  • StringBuffer是线程安全的,StringBuilder是线程不安全的
    • StringBuilder的效率会比StringBuffer效率更高,单线程的程序推荐使用StringBuilder
    • 在多线程的程序中,应该优先考虑使用StringBuffer,安全性要更重要
    • 它们的效率都比String高很多