Skip to content

0459 0497 第十三章 常用类

13.1 包装类(Wrapper)

13.1.1 包装类的分类

  1. 针对八种基本数据类型相应的引用类型—包装类
  2. 有了类的特点,就可以调用类中的方法。
基本数据类型 包装类 父类
boolean Boolean
char Character
byte Byte Number
short Short Number
int Integer Number
long Long Number
float Float Number
double Doubke Number

13.1.2 包装类和基本数据的转换

  1. jdk 5 前的手动装箱和拆箱方式,

    • 包装: 基本类型 -> 包装类型
    • 拆箱:
  2. jdk 5 以后 (含 jdk 5) 的自动装箱和拆箱方式

  3. 自动装箱后层调用的是 valueOf 方法

    • Integer.valueOf ()

4. 其它包装类的用法类似,不一举例

13.1.3 案例演示

public class Integer01 {

    public static void main(String[] args) { 
    //演示 int <--> Integer 的装箱和拆箱
    //jdk5 前是手动装箱和拆箱//手动装箱 int->Integer int n1 = 100;
        Integer integer = new Integer(n1); Integer integer1 = Integer.valueOf(n1);
        //手动拆箱//Integer -> int
        int i = integer.intValue();
        //jdk5 后,就可以自动装箱和自动拆箱int n2 = 200;
        //自动装箱 int->Integer
        Integer integer2 = n2; //底层使用的是 Integer.valueOf(n2) 
        //自动拆箱 Integer->int
        int n3 = integer2; //底层仍然使用的是 intValue()方法
    }
}

13.1.5 包装类型和 String 类型的相互转换

public class WrapperVSString {
    public static void main(String[] args) {
        //包装类(Integer)->String
        Integer i = 100;//自动装箱//方式 1
        String str1 = i + "";
        //方式 2
        String str2 = i.toString();
        //方式 3
        String str3 = String.valueOf(i);
        //String -> 包装类(Integer)
        String str4 = "12345";
        Integer i2 = Integer.parseInt(str4);//使用到自动装箱
        Integer i3 = new Integer(str4);//构造器
        System.out.println("ok~~");
    }
}

13.1.6 Integer 类和 Character 类的常用方法

public class WrapperMethod {
    public static void main(String[] args) {
        System.out.println(Integer.MIN_VALUE); //返回最小值
        System.out.println(Integer.MAX_VALUE);//返回最大值
        System.out.println(Character.isDigit('a'));//判断是不是数字
        System.out.println(Character.isLetter('a'));//判断是不是字母
        System.out.println(Character.isUpperCase('a'));//判断是不是大写
        System.out.println(Character.isLowerCase('a'));//判断是不是小写
        System.out.println(Character.isWhitespace('a'));//判断是不是空格
        System.out.println(Character.toUpperCase('a'));//转成大写
        System.out.println(Character.toLowerCase('A'));//转成小写
    }
}

13.1.7 Integer 类面试题

public class WrapperExercise02 {
    public static void main(String[] args) {
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j); //False
        //所以,这里主要是看范围 -128 ~ 127 就是直接返回
        /*
        老韩解读
        //1. 如果 i 在 IntegerCache.low(-128)~IntegerCache.high(127),就直接从数组返回
        //2. 如果不在 -128~127,就直接 new Integer(i)
        public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
        }
        */
        Integer m = 1; //底层 Integer.valueOf(1); -> 阅读源码
        Integer n = 1;//底层 Integer.valueOf(1);
        System.out.println(m == n); //T
        //所以,这里主要是看范围 -128 ~ 127 就是直接返回
        //,否则,就 new Integer(xx);
        Integer x = 128;//底层 Integer.valueOf(1);
        Integer y = 128;//底层 Integer.valueOf(1);
        System.out.println(x == y);//False
    }
}
public class WrapperExercise03 {
    public static void main(String[] args) {
//示例一
        Integer i1 = new Integer(127);
        Integer i2 = new Integer(127);
        System.out.println(i1 == i2);//F
//示例二
        Integer i3 = new Integer(128);
        Integer i4 = new Integer(128);
        System.out.println(i3 == i4);//F
//示例三
        Integer i5 = 127;//底层 Integer.valueOf(127)
        Integer i6 = 127;//-128~127
        System.out.println(i5 == i6); //T
//示例四
        Integer i7 = 128; Integer i8 = 128;
        System.out.println(i7 == i8);//F
//示例五
        Integer i9 = 127; //Integer.valueOf(127)
        Integer i10 = new Integer(127);
        System.out.println(i9 == i10);//F
//示例六
        Integer i11 = 127;
        int i12 = 127;
//只有有基本数据类型,判断的是
//值是否相同
        System.out.println(i11 == i12); //T
//示例七
        Integer i13 = 128;
        int i14 = 128;
        System.out.println(i13 == i14); //T
    }
}

13.2 String 类

13.2.1 String 类的理解和创建对象

  1. String 对象用于保存字符串,也就是一组字符序列

  2. 字符串常量对象是用双引号括起的字符序列。例如:"你好"、"12.97"、"boy"等

  3. 字符串的字符使用 Unicode 字符编码,一个字符 (不区分字母还是汉字) 占两个字节。

  4. String 类较常用构造器 (其它看手册):

    • String s1 = new String ();
    • String s2 = new String(String original);
    • String s3 = new String(char[] a);
    • String s4 = new String(char[] a,int startlndexjnt count)
  5. String 类实现了接口 Serializable

    • String 可以串行化:可以在网络传输
    • 接口 Comparable :String 对象可以比较大小
  6. String 是 final 类,不能被其他的类继承

  7. String 有属性 private final char value[]; 用于存放字符串内容

  8. value 是一个 final 类型,不可以修改 (需要功力):

    • 即 value 不能指向新的地址
    • 但是单个字符内容是可以变化

13.2.2 创建 String 对象的两种方式

  1. 方式一:直接赋值

    • String s = "123";
  2. 方式二:调用构造器

    • String s = new String("234")

13.2.3 两种创建 String 对象的区别

  1. 方式一:先从常量池直看是否有 "123" 数据空间,如果有,直接指向;

    • 如果没有则重新创建,然后指向。
    • s 最终指向的是常量池的空间地址
  2. 方式二:先在堆中创建空间,里面维护了 value 属性,

    • 指向常量池的 123 空间。
    • 如果常量池没有"hsp", 重新创建
    • 如果有,直接通过 value 指向。
    • 最终指向的是堆中的空间地址

13.3 String 字符串的特性

  1. String 是一个 final 类,代表不可变的字符序列
  2. 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的

13.4 String 类的常见用法

13.4.1 创建新字符串的方法

这些方法会返回一个新的 String 对象,而不会修改原始字符串。

  1. substring (int beginIndex) / substring (int beginIndex, int endIndex)
  2. 功能:提取子字符串。
    • substring(int beginIndex):从 beginIndex 开始到字符串末尾。
    • substring(int beginIndex, int endIndex):从 beginIndexendIndex-1
  3. 返回值:新的子字符串。
  4. 异常:如果索引越界,抛出 IndexOutOfBoundsException
  5. 示例

    String str = "Hello, World";
    String sub1 = str.substring(0, 5); // 返回 "Hello"
    String sub2 = str.substring(7); // 返回 "World"
    

  6. concat (String str)

  7. 功能:将指定字符串连接到当前字符串的末尾。
  8. 返回值:新的字符串(原字符串 + 指定字符串)。
  9. 示例

    String str = "Hello";
    String result = str.concat(", World"); // 返回 "Hello, World"
    

  10. replace (char oldChar, char newChar) / replace (CharSequence target, CharSequence replacement)

  11. 功能
    • replace(char oldChar, char newChar):将字符串中的 oldChar 替换为 newChar
    • replace(CharSequence target, CharSequence replacement):将字符串中的 target 子串替换为 replacement
  12. 返回值:新的字符串(替换后的结果)。
  13. 示例

    String str = "Hello, World";
    String result1 = str.replace('o', '0'); // 返回 "Hell0, W0rld"
    String result2 = str.replace("World", "Java"); // 返回 "Hello, Java"
    

  14. toUpperCase () / toLowerCase ()

  15. 功能
    • toUpperCase():将字符串转换为全大写。
    • toLowerCase():将字符串转换为全小写。
  16. 返回值:新的字符串(转换后的结果)。
  17. 示例

    String str = "Hello, World";
    String upper = str.toUpperCase(); // 返回 "HELLO, WORLD"
    String lower = str.toLowerCase(); // 返回 "hello, world"
    

  18. trim ()

  19. 功能:去除字符串首尾的空白字符(空格、制表符、换行符等,ASCII 码 <= 32)。
  20. 返回值:新的字符串(去除首尾空白后的结果)。
  21. 示例

    String str = "  Hello, World  ";
    String result = str.trim(); // 返回 "Hello, World"
    

  22. replaceAll (String regex, String replacement) / replaceFirst (String regex, String replacement)

  23. 功能
    • replaceAll:使用正则表达式替换所有匹配的子串。
    • replaceFirst:仅替换第一个匹配的子串。
  24. 返回值:新的字符串(替换后的结果)。
  25. 异常:如果正则表达式无效,抛出 PatternSyntaxException
  26. 示例

    String str = "Hello, World, Hello";
    String result1 = str.replaceAll("Hello", "Hi"); // 返回 "Hi, World, Hi"
    String result2 = str.replaceFirst("Hello", "Hi"); // 返回 "Hi, World, Hello"
    

  27. split (String regex) / split (String regex, int limit)

  28. 功能:根据正则表达式将字符串分割为字符串数组。
    • limit:控制分割次数(数组的最大长度)。
  29. 返回值:新的字符串数组。
  30. 异常:如果正则表达式无效,抛出 PatternSyntaxException
  31. 示例

    String str = "a,b,c";
    String[] result = str.split(","); // 返回 {"a", "b", "c"}
    

  32. strip () / stripLeading () / stripTrailing ()(Java 11 及以上)

  33. 功能
    • strip():去除字符串首尾的空白字符(包括 Unicode 空白字符)。
    • stripLeading():仅去除首部空白字符。
    • stripTrailing():仅去除尾部空白字符。
  34. 返回值:新的字符串。
  35. 示例
    String str = "\u2000Hello, World\u2000";
    String result = str.strip(); // 返回 "Hello, World"
    

13.4.2 不创建新字符串的方法

这些方法不修改原始字符串,也不返回新的字符串对象,而是返回其他类型的结果(如布尔值、整数、字符等)。

  1. length ()
  2. 功能:返回字符串的长度(字符数)。
  3. 返回值int 类型。
  4. 示例

    String str = "Hello";
    int len = str.length(); // 返回 5
    

  5. charAt (int index)

  6. 功能:返回指定索引处的字符。
  7. 返回值char 类型。
  8. 异常:如果索引越界,抛出 IndexOutOfBoundsException
  9. 示例

    String str = "Hello";
    char c = str.charAt(1); // 返回 'e'
    

  10. isEmpty ()

  11. 功能:检查字符串是否为空(长度为 0)。
  12. 返回值boolean 类型。
  13. 示例

    String str = "";
    boolean empty = str.isEmpty(); // 返回 true
    

  14. equals (Object obj) / equalsIgnoreCase (String anotherString)

  15. 功能
    • equals:比较字符串内容是否相等。
    • equalsIgnoreCase:忽略大小写比较字符串内容。
  16. 返回值boolean 类型。
  17. 示例

    String str = "Hello";
    boolean eq1 = str.equals("hello"); // 返回 false
    boolean eq2 = str.equalsIgnoreCase("hello"); // 返回 true
    

  18. contains (CharSequence s)

  19. 功能:检查字符串是否包含指定子串。
  20. 返回值boolean 类型。
  21. 示例

    String str = "Hello, World";
    boolean contains = str.contains("World"); // 返回 true
    

  22. startsWith (String prefix) / endsWith (String suffix)

  23. 功能
    • startsWith:检查字符串是否以指定前缀开头。
    • endsWith:检查字符串是否以指定后缀结尾。
  24. 返回值boolean 类型。
  25. 示例

    String str = "Hello, World";
    boolean starts = str.startsWith("Hello"); // 返回 true
    boolean ends = str.endsWith("World"); // 返回 true
    

  26. indexOf (int ch) / indexOf (String str) / lastIndexOf (int ch) / lastIndexOf (String str)

  27. 功能
    • indexOf:返回指定字符或子串第一次出现的索引。
    • lastIndexOf:返回指定字符或子串最后一次出现的索引。
  28. 返回值int 类型(未找到返回 -1)。
  29. 示例

    String str = "Hello, World, Hello";
    int index1 = str.indexOf('o'); // 返回 4
    int index2 = str.indexOf("World"); // 返回 7
    int lastIndex = str.lastIndexOf('o'); // 返回 16
    

  30. isBlank ()(Java 11 及以上)

  31. 功能:检查字符串是否为空或仅包含空白字符(包括 Unicode 空白字符)。
  32. 返回值boolean 类型。
  33. 示例
    String str = "  \u2000  ";
    boolean blank = str.isBlank(); // 返回 true
    

13.4.3 总结

  • 创建新字符串的方法(返回新的 String 对象):
  • substringconcatreplacereplaceAllreplaceFirsttoUpperCasetoLowerCasetrimsplitstripstripLeadingstripTrailing
  • 这些方法因 String 的不可变性,总是返回新的字符串对象。
  • 不创建新字符串的方法(返回非 String 类型,如 booleanintchar):
  • lengthcharAtisEmptyequalsequalsIgnoreCasecontainsstartsWithendsWithindexOflastIndexOfisBlank
  • 这些方法仅查询或比较字符串内容,不涉及字符串内容的修改。
  • 注意事项
  • String 不可变,任何修改操作都会生成新对象,需注意性能(频繁操作可能导致内存开销)。
  • 使用 StringBuilderStringBuffer 可优化频繁的字符串拼接操作。
  • 某些方法(如 substringreplaceAll)可能抛出异常,需注意异常处理。

13.4.4 综合示例

public class StringMethodsExample {
    public static void main(String[] args) {
        String str = "  Hello, World!  ";

        // 创建新字符串的方法
        System.out.println("substring: " + str.substring(2, 7)); // "Hello"
        System.out.println("concat: " + str.concat(" Java")); // "  Hello, World!  Java"
        System.out.println("replace: " + str.replace("World", "Java")); // "  Hello, Java!  "
        System.out.println("toUpperCase: " + str.toUpperCase()); // "  HELLO, WORLD!  "
        System.out.println("trim: " + str.trim()); // "Hello, World!"

        // 不创建新字符串的方法
        System.out.println("length: " + str.length()); // 16
        System.out.println("charAt: " + str.charAt(3)); // 'H'
        System.out.println("isEmpty: " + str.isEmpty()); // false
        System.out.println("contains: " + str.contains("World")); // true
        System.out.println("startsWith: " + str.startsWith("  H")); // true
        System.out.println("indexOf: " + str.indexOf("o")); // 4
    }
}

13.5 StringBuffer 类

13.5.1 基本介绍

  • java. Iang. StringBuffe 代表可变的字符序列,可以对字符串内容进行增删。
  • 很多方法与 String 相同,但 StringBuffer 是可变长度的。
  • StringBuffer 是一个容器

StringBuffer 是 Java 提供的一个可变字符串类,位于 java.lang 包中,设计用于在多线程环境中安全地进行字符串操作。


13.5.2 基本特性

  1. 可变性StringBuffer 的内容可以动态增删改,适合频繁的字符串操作。
  2. 线程安全StringBuffer 的方法大多是同步的(synchronized),因此在多线程环境下是线程安全的。
  3. 性能:由于线程同步的开销,StringBuffer 的性能略低于非线程安全的 StringBuilder
  4. 初始容量:默认初始容量为 16 个字符(可以指定初始容量),当内容超出容量时会自动扩容(通常为当前容量的两倍加 2)。
  5. StringBuffer 的直接父类是 `AbstractStringBuilder
  6. StringBuffer 实现了 Serializable, 即 StringBuffer 的对象可以串行化
  7. 在父类中 AbstractStringBuilder 有属性 char[] value, 不是 final 该 value 数组存放字符串内容,引出存放在堆中的
  8. StringBuffer 是一个 final 类,不能被继承
  9. 因为 StringBuffer 字符内容是存在 char[] value, 所以在变化 (增加/删除) 不用每次都更换地址 (即不是每次创建新对象), 所以效率高于 String

13.5.3 常用构造方法

  • StringBuffer():构造一个空的 StringBuffer,初始容量为 16。
  • StringBuffer(int capacity):指定初始容量。
  • StringBuffer(String str):用给定的字符串初始化。
  • StringBuffer(CharSequence seq):用字符序列初始化。
StringBuffer sb1 = new StringBuffer(); // 空,容量 16
StringBuffer sb2 = new StringBuffer(32); // 空,容量 32
StringBuffer sb3 = new StringBuffer("Hello"); // 初始化为 "Hello"

13.5.4 常用方法

StringBuffer 提供了丰富的字符串操作方法,大多直接修改对象本身并返回 StringBuffer(支持链式调用)。以下是常用方法:

添加内容

  • append(...):在末尾追加内容(支持多种类型:Stringcharintboolean 等)。
  • insert(int offset, ...):在指定位置插入内容。
    StringBuffer sb = new StringBuffer("Hello");
    sb.append(", World"); // 结果:Hello, World
    sb.insert(5, "!"); // 结果:Hello!, World
    

删除内容

  • delete(int start, int end):删除从 start 到 end-1 的字符。
  • deleteCharAt(int index):删除指定索引的字符。
    StringBuffer sb = new StringBuffer("Hello, World");
    sb.delete(5, 12); // 结果:Hello
    sb.deleteCharAt(4); // 结果:Hell
    

修改内容

  • replace(int start, int end, String str):用 str 替换从 start 到 end-1 的内容。
  • setCharAt(int index, char ch):将指定索引的字符替换为 ch
    StringBuffer sb = new StringBuffer("Hello, World");
    sb.replace(7, 12, "Java"); // 结果:Hello, Java
    sb.setCharAt(0, 'h'); // 结果:hello, Java
    

反转

  • reverse():反转字符串内容。
    StringBuffer sb = new StringBuffer("Hello");
    sb.reverse(); // 结果:olleH
    

查询与获取

  • length():返回当前字符串长度。
  • capacity():返回当前容量。
  • charAt(int index):获取指定索引的字符。
  • substring(int start) / substring(int start, int end):提取子字符串(返回新的 String)。
    StringBuffer sb = new StringBuffer("Hello, World");
    int len = sb.length(); // 12
    int cap = sb.capacity(); // 通常 ≥ 12
    char c = sb.charAt(0); // 'H'
    String sub = sb.substring(7, 12); // "World"
    

13.5.5 StringBuffer 与 String 的对比

特性 String StringBuffer
可变性 不可变(immutable),修改生成新对象 可变(mutable),直接修改原对象
线程安全 线程安全(因不可变性) 线程安全(方法同步)
性能 频繁修改时性能差(生成多个对象) 适合频繁修改的场景,性能优于 String
内存占用 每次修改产生新对象,占用内存多 修改在原对象上,内存占用少
适用场景 字符串内容固定或少量修改 频繁拼接、修改(多线程环境)
常用方法 concatsubstringreplace 等 appenddeletereverse 等
初始容量 无(固定大小) 默认 16,可扩容

性能分析

  • String:每次修改(如 + 或 concat)都会创建新对象,导致内存分配和垃圾回收开销。例如:

    String s = "";
    for (int i = 0; i < 1000; i++) {
        s += "a"; // 每次循环创建新对象
    }
    

    上述代码会生成大量临时对象,效率低下。 - StringBuffer:修改操作(如 append)直接在内部字符数组上进行,避免频繁创建对象:

    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < 6; i++) {
        sb.append("a"); // 在同一对象上操作
    }
    

使用场景

  • String:适合多线程环境下少量字符串操作,或字符串内容不经常变化的场景(如常量字符串)。
  • StringBuffer:适合多线程环境下频繁进行字符串操作的场景(如日志拼接、动态构建字符串)。

13.5.6 StringBuffer 与 String 的相互转换

String 转换为 StringBuffer

有以下几种方式:

  • 通过构造方法

    String str = "Hello";
    StringBuffer sb = new StringBuffer(str);
    

  • 通过 append 方法

    String str = "Hello";
    StringBuffer sb = new StringBuffer().append(str);
    

StringBuffer 转换为 String

有以下方式:

  • 通过 toString() 方法

    StringBuffer sb = new StringBuffer("Hello");
    String str = sb.toString(); // "Hello"
    

  • 通过 substring() 方法(间接)

    StringBuffer sb = new StringBuffer("Hello");
    String str = sb.substring(0, sb.length()); // "Hello"
    

  • 通过构造器

    String stringBuffer =  new StringBuffer("111");
    String s1 = new String(stringBuffer);
    

示例代码(综合)

public class StringBufferExample {
    public static void main(String[] args) {
        // String 转 StringBuffer
        String str = "Hello";
        StringBuffer sb1 = new StringBuffer(str);
        System.out.println("String to StringBuffer: " + sb1); // Hello

        // StringBuffer 操作
        sb1.append(", World").insert(5, "!").replace(7, 12, "Java");
        System.out.println("After operations: " + sb1); // Hello!, Java

        // StringBuffer 转 String
        String result = sb1.toString();
        System.out.println("StringBuffer to String: " + result); // Hello!, Java

        // 性能对比
        String s = "";
        StringBuffer sb2 = new StringBuffer();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            s += "a";
        }
        long stringTime = System.currentTimeMillis() - start;
        System.out.println("String time: " + stringTime + "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            sb2.append("a");
        }
        long bufferTime = System.currentTimeMillis() - start;
        System.out.println("StringBuffer time: " + bufferTime + "ms");
    }
}

13.5.7 与 StringBuilder 的简要对比

  • StringBuffer:线程安全,适合多线程环境,但性能稍低。
  • StringBuilder(Java 5 引入):非线程安全,适合单线程环境,性能更高。
  • 选择建议
    • 多线程:优先 StringBuffer
    • 单线程或线程安全由外部控制:优先 StringBuilder
    • 少量修改或不可变需求:使用 String

13.6 StringBuilder 类

13.6.1 基本介绍

  1. 一个可变的字符序列
  2. 此类提供一个与 StringBuffer 兼容的 API, 但不保证同(StringBuilder 不是线程安全)。
  3. 该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候
  4. 如果可能,建议优先采用该类, 因为在大多数实现中,它比 StringBuffer 要快
  5. 在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。

13.6.2 StringBuilder 常用方法

StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所以使用和 StringBuffer 一样

  1. StringBuilder 是 final 类, 不能被继承
  2. 继承了 AbstractStringBuilder, 属性 char[] value , 内容存到 value,因此,字符序列是堆中
  3. 实现了 Serializable ,说明 StringBuilder 对象是可以串行化 (对象可以网络传输, 可以保存到文件)
  4. StringBuilder 继承 AbstractStringBuilder 类
  5. StringBuilder 的方法,没有做互斥的处理, 即没有 synchronized 关键字, 因此在单线程的情况下使用

13.6.3 String、 StringBuffer 和 StringBuilder 的比较

  1. StringBuilder 也一样 StringBuffer 非常类似,均代表可变的字符序列,而且方法也一样
  2. String: 不可变字符序列, 效率低,但是复用率高。
  3. StringBuffer: 可变字符序列、效率较高 (增删)、线程安全, 看源码
  4. StringBuilder: 可变字符序列、效率最高、线程不安全
  5. String 使用注意说明:
    • string s=”a"; 〃创建了一个字符串
    • s+= "b"; 〃实际上原来的”a”字符串对象已经丢弃了,现在又产生了一个字符 s+”b” 也就是 "ab"
    • 如果多次执行这些改变事内容的操作,会导致大量副本字符串对象存留在内存中,降低效率
    • 如果这样的操作放到循环中,会极大影响程序的性能
  6. 如果我们对 String 做大量修改,不要使用 String

13.6.4 String、 StringBuffer 和 StringBuilder 的效率测试

效率 : StringBuilder > StringBuffer > String

  • 原因StringBuilder 比 StringBuffer 快是因为它不使用同步机制,避免了锁的获取和释放开销。
  • 选择建议
    • 单线程或性能优先:选择 StringBuilder
    • 多线程且需要线程安全:选择 StringBuffer
public class StringVsStringBufferVsStringBuilder {
    public static void main(String[] args) {
        long startTime = 0L;
        long endTime = 0L;

        StringBuffer buffer = new StringBuffer("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {//StringBuffer 拼接 20000 次
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer 的执行时间: " + (endTime - startTime));

        StringBuilder builder = new StringBuilder("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {//StringBuilder 拼接 20000 次
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder 的执行时间: " + (endTime - startTime));

        String text = "";
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {//String 拼接 20000
            text = text + i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String 的执行时间: " + (endTime - startTime));
    }
}

13.7 Math 类

13.7.1 基本介绍

Math 类包含用于基本数学运算的静态方法和常量,涵盖初等指数、对数、平方根、三角函数等操作。由于构造方法是私有的,无法实例化对象,方法通过 Math.<方法名> 调用。常用场景包括数值计算、随机数生成和几何运算等。


13.7.3 Math 类常见常量和方法

常用常量

  • Math.PI:圆周率,约等于 \(π≈3.141592653589793\)
  • Math.E:自然对数的底数,约等于 \(e≈2.718281828459045\)

常见方法

绝对值与比较
  • Math.abs(double a):返回参数的绝对值,支持 intlongfloatdouble
  • Math.max(double a, double b):返回两数中的较大值,支持多种类型。
  • Math.min(double a, double b):返回两数中的较小值,支持多种类型。
取整操作
  • Math.ceil(double a):向上取整,返回大于或等于 a 的最小整数。
  • Math.floor(double a):向下取整,返回小于或等于 a 的最大整数。
  • Math.round(double a):四舍五入,返回最接近的 longfloat 返回 int)。
  • Math.rint(double a):返回最接近的整数(若两个整数等距,返回偶数)。
指数与对数
  • Math.pow(double a, double b):计算 \(a^b\),返回 \(a\) 的 \(b\) 次幂。
  • Math.exp(double a):计算 \(e^a\),返回自然底数的指数。
  • Math.log(double a):计算以 \(e\) 为底的对数 \(ln(a)\)
  • Math.log10(double a):计算以 10 为底的对数 \(log⁡_{10} (a)\) ​。
  • Math.sqrt(double a):计算平方根 \(\sqrt a\) ​。
  • Math.cbrt(double a):计算立方根 \(\sqrt[3] a\) ​。
三角函数

参数以弧度为单位(可用 Math.toRadians 转换角度)。

  • Math.sin(double a):计算正弦 \(sin(a)\)
  • Math.cos(double a):计算余弦 \(cos(a)\)
  • Math.tan(double a):计算正切 \(tan(a)\)
  • Math.asin(double a):计算反正弦 \(arcsin(a)\),范围 \([ \frac {−π}{2},\frac{π}{2}]\)
  • Math.acos(double a):计算反余弦 \(arccos(a)\),范围 \([0,π]\)
  • Math.atan(double a):计算反正切 \(arctan(a)\),范围 \([ \frac {−π}{2},\frac{π}{2}]\)
    double rad = Math.toRadians(90); // 90° 转为弧度
    System.out.println(Math.sin(rad)); // 1.0
    System.out.println(Math.cos(Math.toRadians(0))); // 1.0
    System.out.println(Math.toDegrees(Math.asin(0.5))); // 30.0
    
随机数
  • Math.random():生成 \([0.0,1.0)\) 之间的随机 double 值。
    System.out.println(Math.random()); // 例:0.723942837
    // 生成 [1, 100] 的随机整数
    int randomInt = (int)(Math.random() * 100) + 1;
    System.out.println(randomInt); // 例:73
    
其他方法
  • Math.toRadians(double angdeg):将角度转换为弧度。
  • Math.toDegrees(double angrad):将弧度转换为角度。
  • Math.hypot(double x, double y):计算 \(\sqrt{{x^2} +{y^2}}\) ​,避免溢出。
  • Math.IEEEremainder(double f1, double f2):计算 IEEE 余数 \(f1 - f2 \times n\),其中 \(n\) 是最接近 \(\frac{f1}{f2}\) 的整数。
    System.out.println(Math.toDegrees(Math.PI / 2)); // 90.0
    System.out.println(Math.hypot(3, 4)); // 5.0
    System.out.println(Math.IEEEremainder(10, 3)); // 1.0
    
注意事项
  1. 精度问题:浮点运算可能存在精度误差(如 Math.sin(Math.PI/2) 可能接近但不精确等于 1.0)。
  2. 参数单位:三角函数以弧度为单位,需用 Math.toRadians 转换角度。
  3. 性能Math 方法为静态方法,调用方便,但高精度计算建议使用 StrictMath 类。
  4. 随机数:对于更复杂的随机数需求,推荐使用 java.util.Random 或 ThreadLocalRandom

13.8 Arrays 类

java.util.Arrays 是一个工具类,提供了大量静态方法用于操作数组,如排序、查找、复制、填充和转换等。无需实例化,直接通过类名调用。其方法适用于基本数据类型和引用类型的数组,广泛应用于数据处理、算法实现等场景。


13.8.1 Arrays 类常见方法应用案例

1. toStringdeepToString

  • 功能:将数组转换为字符串表示。toString 适用于一维数组,deepToString 适用于多维数组。
  • 应用场景:调试或输出数组内容。
  • 案例:打印一维和多维数组。
    int[] arr = {3, 1, 4, 1, 5}; int[][] arr2D = {{1, 2}, {3, 4}}; System.out.println(Arrays.toString(arr)); // [3, 1, 4, 1, 5]
    System.out.println(Arrays.deepToString(arr2D)); // [[1, 2], [3, 4]]
    

输出:便于检查数组内容,避免直接打印数组对象地址(如 [I@123456

2. sort

  • 功能:对数组排序,默认升序,支持全部或部分排序,可通过 Comparator 自定义排序规则。[[Comparator]]
  • 应用场景:数据排序、排行榜、预处理二分查找。
  • 案例:对学生成绩升序排序,部分降序排序。
int[] scores = {85, 70, 90, 65, 95};
Arrays.sort(scores); // 升序
System.out.println(Arrays.toString(scores)); // [65, 70, 85, 90, 95]

Integer[] scores2 = {85, 70, 90, 65, 95};
Arrays.sort(scores2, 0, 3, (a, b) -> b - a); // 前 3 个降序
System.out.println(Arrays.toString(scores2)); // [90, 85, 70, 65, 95]

输出:排序后的成绩便于统计最高/最低分。

3. binarySearch

  • 功能:在有序数组中进行二分查找,返回目标元素的索引,未找到返回负数(-(插入点+1))。
  • 应用场景:快速查找元素,如查找学生 ID。
  • 案例:查找有序数组中的元素。
int[] sorted = {1, 3, 5, 7, 9};
int index = Arrays.binarySearch(sorted, 5); // 找到 5
System.out.println(index); // 2
index = Arrays.binarySearch(sorted, 4); // 未找到 4
System.out.println(index); // -3(插入点为 2)

注意:数组必须先排序,否则结果不可预测。

4. copyOf 和 copyOfRange

  • 功能copyOf 复制整个数组到指定长度copyOfRange 复制指定范围。
  • 应用场景:备份数组、截取子数组。
  • 案例:复制成绩数组并截取部分数据。
int[] scores = {85, 70, 90, 65, 95};
int[] copy = Arrays.copyOf(scores, 3); // 前 3 个
int[] range = Arrays.copyOfRange(scores, 1, 4); // 索引 1 到 3
System.out.println(Arrays.toString(copy)); // [85, 70, 90]
System.out.println(Arrays.toString(range)); // [70, 90, 65]

输出:复制结果可用于数据分析或临时存储。

5. fill

  • 功能:用指定值填充整个数组或指定范围。
  • 应用场景:初始化数组、设置默认值。
  • 案例:初始化考试分数为 0。
int[] scores = new int[5];
Arrays.fill(scores, 0); // 全填充
System.out.println(Arrays.toString(scores)); // [0, 0, 0, 0, 0]
Arrays.fill(scores, 1, 3, 100); // 部分填充
System.out.println(Arrays.toString(scores)); // [0, 100, 100, 0, 0]

6. equals 和 deepEquals

  • 功能:比较两个数组是否相等。equals 用于一维数组,deepEquals 用于多维数组。
  • 应用场景:验证数组内容一致性。
  • 案例:比较两组学生成绩。
int[] scores1 = {85, 70, 90};
int[] scores2 = {85, 70, 90};
int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 4}};
System.out.println(Arrays.equals(scores1, scores2)); // true
System.out.println(Arrays.deepEquals(matrix1, matrix2)); // true

7. asList

  • 功能:将数组转换为固定大小的 List
  • 应用场景:将数组与集合操作结合使用。
  • 案例:将字符串数组转为 List 处理。
String[] names = {"Alice", "Bob", "Charlie"};
List<String> list = Arrays.asList(names);
System.out.println(list); // [Alice, Bob, Charlie]
// list.add("Dave"); // 抛出 UnsupportedOperationException

注意:返回的 List 是只读的,不支持 add 或 remove 操作。

注意事项

  1. 类型一致性asList 要求数组元素类型一致(如 Integer[] 而非 int[]),否则可能导致意外行为。
  2. 排序前提binarySearch 要求数组已排序,否则结果不可靠。
  3. 只读 ListasList 返回的 List 不支持增删操作,需转为 java.util.ArrayList 才能修改。
  4. 性能考虑sort 使用双轴快速排序,适合大部分场景;parallelSort 适用于大数组并行排序。

13.8.2 手动实现 Comparator 的冒泡

import java.util.Comparator;  

class Main{  
    public static void main(String[] args) {  
        int[] arr = {1, 5, 3, 9, 7, 2};  
        bubble(arr);  

        System.out.println("排序后:");  
        for (int j : arr) {  
            System.out.print(j + " ");  
        }  

        System.out.println("从大到小");  
        enhanceBubble(arr, new Comparator() {  
            @Override  
            public int compare(Object o1, Object o2) {  
                return (int) o2 - (int) o1;  
            }  
        });  
        System.out.println("排序后:");  
        for (int j : arr) {  
            System.out.print(j + " ");  
        }  
    }  

    public static void bubble(int[] arr){  
        int temp = 0;  
        for (int i = 0; i < arr.length -1 ; i++) {  
            for (int j = 0; j < arr.length - 1 - i; j++){  
                // 从小到大  
                if (arr[j] > arr[j+1]){  
                    temp = arr[j];  
                    arr[j] = arr[j+1];  
                    arr[j+1] = temp;  
                }  
            }  
        }  
    }  

    public static void enhanceBubble(int[] arr, Comparator c){  
        int temp = 0;  
        for (int i = 0; i < arr.length -1 ; i++){  
            for (int j = 0; j < arr.length - 1 - i; j++){  
                if (c.compare(arr[j], arr[j+1]) > 0){  
                    temp = arr[j];  
                    arr[j] = arr[j+1];  
                    arr[j+1] = temp;  
                }  
            }  
        }  
    }  
}

[[Comparator#升序降序|调整升序和降序]]


13.9 System 类

  1. exit: 退出当前程序

  2. arraycopy : 复制数组元素,比较适合底层调用,一般使用 Arrays.copyOf 完成复制数组. int[] src={1,2,3}; int[] dest = new int[3]; System.arraycopy(src, 0, dest, 0, 3);

    • 方法签名
      • public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
    • 参数说明
      • src:源数组。
      • srcPos:源数组的起始位置(从 0 开始)。
      • dest:目标数组。
      • destPos:目标数组的起始位置。
      • length:要复制的元素个数。
    • 功能
      • 将源数组 src 从 srcPos 开始的 length 个元素,复制到目标数组 dest 的 destPos 位置开始处。
      • 支持任意类型数组(基本类型或引用类型)。
  3. currentTimeMillens: 返回当前时间距离 \(1970-1-1\) 的毫秒数

  4. gc : 运行垃圾回收机制 System.gc().


13.10 BigInteger 和 BigDecimal 类

Biginteger 适合保存比较大的整型 BigDecimal 适合保存精度更高的浮点型 (小数)


13.10.2 BigInteger 和 BigDecimal 常见方法

BigInteger 常见方法

BigInteger 用于表示任意精度的整数,常用于大数运算。

  1. 构造方法

    • BigInteger(String val):从字符串创建大整数,如 new BigInteger("123456789")
    • BigInteger(byte[] val):从字节数组创建大整数。
    • valueOf(long val):从 long 值创建,如 BigInteger.valueOf(123)
  2. 基本运算

    • add(BigInteger val):加法,返回 this + val
    • subtract(BigInteger val):减法,返回 this - val
    • multiply(BigInteger val):乘法,返回 this * val
    • divide(BigInteger val):除法(整除),返回 this / val
    • remainder(BigInteger val):取余,返回 this % val
    • pow(int exponent):幂运算,返回 this^exponent
  3. 比较

    • compareTo(BigInteger val):比较大小,<0 表示 this < val=0 表示相等,>0 表示 this > val
    • equals(Object x):判断是否相等。
    • min(BigInteger val) / max(BigInteger val):返回较小/较大值。
  4. 其他实用方法

    • abs():返回绝对值。
    • negate():返回相反数。
    • gcd(BigInteger val):返回最大公约数。
    • mod(BigInteger m):模运算,返回 this mod m(常用于加密算法)。
    • toString():转换为字符串表示。
    • intValue() / longValue():转换为 int 或 long(可能丢失精度)。

示例

BigInteger a = new BigInteger("123");
BigInteger b = new BigInteger("456");
System.out.println(a.add(b)); // 579
System.out.println(a.multiply(b)); // 56088
System.out.println(a.compareTo(b)); // -1 (123 < 456)

BigDecimal 常见方法

BigDecimal 用于高精度浮点运算,适合金融计算等需要精确小数的场景。

  1. 构造方法

    • BigDecimal(String val):从字符串创建,如 new BigDecimal("123.456")
    • BigDecimal(double val):从 double 创建(不推荐,可能有精度问题)。
    • valueOf(double val):从 double 创建,推荐使用。
  2. 基本运算

    • add(BigDecimal augend):加法,返回 this + augend
    • subtract(BigDecimal subtrahend):减法,返回 this - subtrahend
    • multiply(BigDecimal multiplicand):乘法,返回 this * multiplicand
    • divide(BigDecimal divisor, int scale, RoundingMode roundingMode):除法,指定精度和舍入模式(如 RoundingMode.HALF_UP)。
  3. 比较

    • compareTo(BigDecimal val):比较大小,<0 表示 this < val=0 表示相等,>0 表示 this > val
    • equals(Object x):判断值和精度是否完全相等。
    • min(BigDecimal val) / max(BigDecimal val):返回较小/较大值。
  4. 其他实用方法

    • setScale(int newScale, RoundingMode roundingMode):设置精度和舍入模式。
    • abs():返回绝对值。
    • negate():返回相反数。
    • round(MathContext mc):根据指定上下文舍入。
    • toString():转换为字符串。
    • doubleValue() / floatValue():转换为 double 或 float(可能丢失精度)。

示例

BigDecimal a = new BigDecimal("123.456");
BigDecimal b = new BigDecimal("7.89");
System.out.println(a.add(b)); // 131.346
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP)); // 15.65
System.out.println(a.setScale(1, RoundingMode.HALF_UP)); // 123.5

注意事项

  1. BigInteger

    • 运算结果仍为 BigInteger,不可变(immutable)。
    • 除法和取余需确保除数非零,否则抛 ArithmeticException
    • 适合加密、数学计算等场景。
    • BigDecimal

    • 除法必须指定精度和舍入模式,否则可能抛 ArithmeticException(如无法整除)。

      • BigDecimal.ROUND_CEILING 保留分子精度
      • BigDecimal.divide (bigdecimal, BigDecimal. ROUND_CEILING)
    • 避免用 double 构造(如 new BigDecimal(0.1)),因 double 本身不精确,推荐用字符串。或者指定精度
    • 适合金融、货币计算,确保精度。
    • 性能:两者运算比基本类型慢,适合精度要求高的场景。

13.11日期类

13.11.1 第一代: java.util.Date 和 java.util.Calendar

时间:JDK 1.0(1996)引入 Date,JDK 1.1(1997)引入 Calendar

1. java.util.Date

  • 概述:表示日期和时间的类,存储毫秒级时间戳(从 1970-01-01 00:00:00 UTC 起)。
  • 主要方法
    • Date():创建当前时间对象。
    • Date(long time):根据毫秒时间戳创建。
    • getTime():返回毫秒时间戳。
    • setTime(long time):设置时间戳。
    • before(Date when) / after(Date when):比较时间先后。
  • 缺点
    • 不支持国际化(时区处理差)。
    • 方法混乱(如 getYear() 返回年份减 1900)。
    • 非线程安全。
    • 部分方法(如日期操作)在 JDK 1.1 后废弃,推荐用 Calendar

2. java.util.Calendar

  • 概述:抽象类,提供更丰富的日期操作功能,支持时区和字段操作(如年、月、日)。
  • 常用实现GregorianCalendar(公历实现)。
  • 主要方法
    • get(int field):获取字段值(如 Calendar.YEARCalendar.MONTH)。
    • set(int field, int value):设置字段值。
    • add(int field, int amount):增加/减少字段值(如加 1 月)。
    • getTime():转换为 Date 对象。
    • setTime(Date date):从 Date 设置时间。
  • 缺点
    • API 复杂,易出错(如 MONTH 从 0 开始计数)。
    • 非线程安全。
    • 可变对象,修改可能引发副作用。
    • 时区和国际化支持有限。
    • 不能处理闰秒

应用场景:早期 Java 程序,简单日期处理。

示例

Date date = new Date();
System.out.println(date); // 当前时间
Calendar cal = Calendar.getInstance();
cal.set(2025, Calendar.JULY, 27); // 2025-07-27
System.out.println(cal.getTime()); // Sun Jul 27 00:00:00 CST 2025

13.11.2 第二代:java.text.SimpleDateFormat

时间:JDK 1.1(1997)引入。

  • 概述:用于格式化和解析日期字符串,常与 Date 配合使用,属于 java.text 包。
  • 主要方法
    • SimpleDateFormat(String pattern):定义格式,如 "yyyy-MM-dd HH:mm:ss"
    • format(Date date):将 Date 格式化为字符串。
    • parse(String text):将字符串解析为 Date
  • 特点
    • 支持自定义格式(如 "yyyy-MM-dd")。
    • 便于日期字符串转换。
  • 缺点
    • 非线程安全(多线程需同步或用 ThreadLocal)。
    • 依赖 Date,继承其缺点。
    • 解析复杂日期字符串时易出错。

应用场景:日期格式化、字符串解析。

示例

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2025-07-27");
System.out.println(sdf.format(date)); // 2025-07-27

13.11.3 第三代:java.time 包(JSR-310)

时间:JDK 8(2014)引入。

  • 概述:基于 JSR-310 规范的现代日期时间 API,位于 java.time 包,设计优雅,解决前两代缺陷。
  • 核心类

    • LocalDate:仅日期(如 2025-07-27)。
    • LocalTime:仅时间(如 15:01:19)。
    • LocalDateTime:日期+时间(如 2025-07-27T15:01:19)。
    • ZonedDateTime:带时区的日期时间。
    • Instant:时间戳(类似 Date 的毫秒表示)。可以转换成 Date 类
    • Duration / Period:时间间隔(秒/天级别)。
  • 主要方法(以 LocalDate 和 LocalDateTime 为例):

    • now():获取当前日期/时间。
    • of(int year, int month, int day):创建指定日期。
    • plusDays(long days) / minusMonths(long months):加减时间单位。
    • getYear() / getMonth():获取字段值(直观,无偏移)。
    • atTime(int hour, int minute):结合时间(如 LocalDate 转为 LocalDateTime)。
    • format(DateTimeFormatter formatter):格式化。
    • parse(CharSequence text, DateTimeFormatter formatter):解析字符串。
  • 特点

    • 不可变:线程安全,每次操作返回新对象。
    • 清晰 API:方法名直观,易用。
    • 时区支持ZonedDateTime 和 ZoneId 处理国际化。
    • 高精度:支持纳秒级操作。
    • 格式化DateTimeFormatter 替代 SimpleDateFormat,线程安全。
  • 优点

    • 解决 Date 和 Calendar 的设计缺陷。
    • 支持现代日期时间需求(如 ISO 8601 标准)。
    • 代码简洁,易于维护。

应用场景:现代 Java 应用,推荐使用,尤其涉及复杂日期、时区、国际化场景。

示例

LocalDate date = LocalDate.of(2025, 7, 27);
System.out.println(date.plusDays(1)); // 2025-07-28
LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(dateTime.format(formatter)); // 如 2025-07-27 15:01:19
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(zdt); // 如 2025-07-27T15:01:19+08:00[Asia/Shanghai]