12_String

# String

String 核心特性

String 是 java.lang 包下的核心类,用于表示字符串。Java 中所有双引号包裹的字符串字面量,本质都是 String 类的实例。

不可变性

String 是不可变字符序列,对象一旦创建,其内容无法修改。

– 底层:JDK 8 及之前用 private final char[] value 存储字符;JDK 9 及之后改为 byte[] 节省空间
– 原因:数组被 final 修饰且私有,类不对外暴露修改数组的方法,所有 “修改” 操作都会返回新的 String 对象
– 优势:安全、可缓存复用、哈希值可缓存

字符串常量池

Java 为了节省内存、提升性能,设计了字符串常量池:

– 直接使用双引号赋值的字符串,会先检查常量池,存在则直接复用,不存在则创建后放入池中
– new String("abc") 一定会在堆中创建新对象,同时也会检查常量池
– intern() 方法:主动将字符串对象加入常量池并返回池中的引用

比较方式 基本数据类型 引用数据类型
== 比较数值是否相等 比较内存地址是否相等(是否为同一个对象)
equals() 无(基本类型不能调用) String 重写后比较字符串内容是否相等

image-20260727191842550

   String str1 = "abc";
        String str2 = new String();
        String str3 = "abc";

        System.out.println(str1 == str2);//false
        System.out.println(str1 == str3);//true
        System.out.println(str2 == str3);//false

        //全为true
        System.out.println(str1.equals(str2));
        System.out.println(str1.equals(str3));
        System.out.println(str2.equals(str3));

String 常用方法:

方法 作用
int length() 返回字符串长度
char charAt(int index) 获取指定索引位置的字符
int indexOf(String str) 查找子串第一次出现索引,找不到返回 -1
int indexOf(String str,int formIndex) 查找str在formIndex之后出现的位置 是左闭区间
int lastIndexOf(String str) 查找子串最后一次出现索引
String substring(int beginIndex) 截取从 begin 到结尾的子串
String substring(int beginIndex, int endIndex) 截取 [begin, end)
boolean equals(Object obj) 比较字符串内容是否相等(区分大小写)
boolean equalsIgnoreCase(String another) 比较内容,不区分大小写
boolean contains(CharSequence s) 判断是否包含子串
boolean startsWith(String prefix) 判断是否以 prefix 开头
boolean endsWith(String suffix) 判断是否以 suffix 结尾
String toUpperCase() 转大写
String toLowerCase() 转小写
String trim() 去除首尾空白字符
String strip() 去除首尾空白字符(Java 11+,支持 Unicode 空白)
String[] split(String regex) 按正则表达式分割字符串
char[] toCharArray() 转成字符数组
byte[] getBytes() 转成字节数组
String replace(old, new) 替换所有匹配的子串
String valueOf(Object obj) 静态方法,把任意类型转成字符串
@Test
public void test2() {
    String str = "java AndroidA";
    System.out.println(str.length());//13
    char[] chars = str.toCharArray();
    char ch = str.charAt(5);//A
    System.out.println(ch);
    System.out.println(str.indexOf('A'));//5
    System.out.println(str.indexOf('X'));//-1 找不到返回-1
    System.out.println(str.indexOf('A', 6));//12
    System.out.println(str.indexOf("And"));//5
    System.out.println(str.lastIndexOf('A'));//12
}

@Test
public void test3() {
    String str1 = "java";
    String str2 = "Java";
    System.out.println(str1.equals(str2));//false
    System.out.println(str1.equalsIgnoreCase(str2));//true

    String str = "java AndroidA";
    System.out.println(str.contains("And"));//true
    System.out.println(str.startsWith("java"));//true
    //offset:偏移
    System.out.println(str.startsWith("And", 5));//true
    System.out.println(str.endsWith("oidA"));//true
    System.out.println(str.isEmpty());//false
    //"":空字符串,也是一个对象   ' '
    System.out.println("".isEmpty());//true
    char ch = ' ';
}

@Test
public void test44() {
    // ""
    //String str = "java And";
    char[] array = {'j', 'a', 'v', 'a', ' ', 'A', 'n', 'd'};
    String str = new String(array);
    System.out.println(str);//java And
    char[] chars = str.toCharArray();
    System.out.println(chars);
    //Arrays:操作数组的工具类
    System.out.println(Arrays.toString(chars));
    //[j, a, v, a,  , A, n, d]
}

@Test
public void test424() {
    String str = "java AndroidA";
    String newStr = str.replace('A', 'B');
    System.out.println(str);//java AndroidA
    System.out.println(newStr);//java BndroidB
}

@Test
public void test66() {
    String str = "java android python";
    String[] array = str.split(" ");
    System.out.println(Arrays.toString(array));
}

@Test
public void test87() {
    // subtree: 子树
    // substring:子字符串
    String str = "java AndroidA";
    System.out.println(str.substring(5));//AndroidA

    //beginIndex – the beginning index, inclusive.
    //endIndex – the ending index, exclusive.
    System.out.println(str.substring(5, 8));//And
}

@Test
public void test181() {
    String str = "    java AndroidA    ";
    String newStr = str.trim();
    System.out.println(str);//    java AndroidA
    System.out.println(newStr);//java AndroidA
}

@Test
public void test88() {
    String str = "Java:Andorid:PHP:Python";
    String[] array = str.split(":");
    //System.out.println(array);
    System.out.println(Arrays.toString(array));//[Java, Andorid, PHP, Python]
}

StringBuilder 与 StringBuffer

由于 String 不可变,频繁拼接字符串会创建很多临时对象,性能差,所以用 StringBuilder 或 StringBuffer,它们内容可变,适合频繁拼接。

类 可变 线程安全 性能 使用场景
String 不可变 – 慢,频繁拼接产生垃圾 内容不频繁改变
StringBuilder 可变 不安全 快 单线程,频繁拼接
StringBuffer 可变 安全,方法加 synchronized 慢 多线程,频繁拼接

💡 推荐:大部分情况用 StringBuilder。

常用方法:

// 创建 StringBuilder
StringBuilder sb = new StringBuilder();

// 拼接 append,支持多种类型
sb.append("Hello");
sb.append(" World");
sb.append(123);
System.out.println(sb); // Hello World123

// insert 插入
sb.insert(5, ","); // 在索引 5 插入逗号

// delete 删除
sb.delete(0, 5); // 删除 [0,5)

// replace 替换
sb.replace(0, 5, "Hi");

// reverse 反转
sb.reverse();

// 转成 String
String result = sb.toString();

示例:高效拼接:

// 不好:每次拼接都创建新对象
String s = "";
for (int i = 0; i < 10000; i++) {
    s = s + i; // 频繁创建新对象,性能差
}

// 好:用 StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    sb.append(i); // 在原有对象上修改,不创建新对象,性能好
}
String result = sb.toString();
@Test
public void test55() {
    String str1 = "Java";
    String str2 = "PHP";
    String str3 = "Python";
    String str4 = "UI";
    String str = str1 + str2 + str3 + str4;//创建很多新对象,效率低
    System.out.println(str);

    StringBuffer buffer = new StringBuffer("C");
//  buffer.append(str1);
//  buffer.append(str2);
//  buffer.append(str3);
//  buffer.append(str4);
    //链式编程
    buffer.append(str1).append(str2).append(str3).append(str4);
    System.out.println(buffer);

    StringBuilder builder = new StringBuilder("C");
//  builder.append(str1);
//  builder.append(str2);
//  builder.append(str3);
//  builder.append(str4);
    builder.append(str1).append(str2).append(str3).append(str4);
    System.out.println(builder);

    System.out.println("------------------");
    //toString 不为打印,作用是转换为字符串
    String str = builder.toString();
    System.out.println(str);
}

包装数据类型

Java是纯面向对象语言,int、double都是基本数据类型。

包装数据类型是对基本数据类型的封装,为引用数据类型,默认值都为null

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

Java 5 之后提供自动装箱 / 拆箱机制,基本类型和包装类可以自动转换:

  • 自动装箱:基本类型 → 包装类,底层调用 valueOf() 方法
  • 自动拆箱:包装类 → 基本类型,底层调用 xxxValue() 方法
@Test
public void test45() {
    //public static final int   MAX_VALUE = 0x7fffffff;
    System.out.println(Integer.MAX_VALUE);

    //自动装箱和自动拆箱
    Integer integer1 = Integer.valueOf(4);
    System.out.println(integer1);//4
    Integer integer2 = 4;//自动装箱
    System.out.println(integer2);//4
    //int i = integer2.intValue();
    int num1 = integer2;//自动拆箱
    System.out.println(num1);//4

    Integer integer = 3;
    int num2 = integer + 4;
    integer = integer + 5;
}

包装类的核心用途:类型转换

包装类最常用的场景是:基本数据类型与字符串之间的相互转换。

(1)基本类型 → 字符串

// 方式1:拼接空字符串
String str1 = 123 + "";

// 方式2:包装类 toString() 方法
String str2 = Integer.toString(3);
String str3 = Double.toString(3.14);

// 方式3:String.valueOf() 静态方法
String str4 = String.valueOf(100);

(2)字符串 → 基本类型

// 方式1:parseXxx() 静态方法(最常用)
int num1 = Integer.parseInt("23");
double num2 = Double.parseDouble("3.14");
boolean flag = Boolean.parseBoolean("true");

// 方式2:valueOf() 先转包装类,再自动拆箱
int num3 = Integer.valueOf("4");

String 与数组的互转

// 1. String → char 数组
String str = "hello";
char[] chars = str.toCharArray();

// 2. char 数组 → String
// 方式1:构造方法
String s1 = new String(chars);
// 方式2:valueOf 静态方法
String s2 = String.valueOf(chars);
上一篇
下一篇