Java String类深度解析

33 阅读8分钟

一、String类概述

在Java中,String类是专门用于处理字符串的引用数据类型。与C语言中通过字符数组或指针处理字符串不同,Java将字符串封装成对象,并提供了丰富的方法来操作字符串,这体现了面向对象的设计思想。

java

// Java中的String类使用示例
public class StringIntroduction {
    public static void main(String[] args) {
        // 与C语言字符数组的对比
        char[] cStr = {'H', 'e', 'l', 'l', 'o'};  // C风格
        String javaStr = "Hello";                  // Java风格
        
        System.out.println("C风格字符串长度: " + cStr.length);
        System.out.println("Java字符串长度: " + javaStr.length());
    }
}

二、String对象的创建方式

2.1 三种常用构造方法

java

public class StringConstruction {
    public static void main(String[] args) {
        // 1. 直接赋值(字面量方式)
        String name1 = "小明";
        
        // 2. 使用new关键字创建对象
        String name2 = new String("小华");
        
        // 3. 通过字符数组创建
        char[] charArray = {'1', '2', '3', '4'};
        String name3 = new String(charArray);
        
        // 4. 其他构造方法
        byte[] byteArray = {65, 66, 67, 68};  // ASCII码
        String name4 = new String(byteArray);
        
        System.out.println("name1: " + name1);
        System.out.println("name2: " + name2);
        System.out.println("name3: " + name3);
        System.out.println("name4: " + name4);
    }
}

2.2 内存模型分析

java

public class StringMemoryModel {
    public static void main(String[] args) {
        // 字符串常量池概念
        String s1 = "Java";          // 在常量池中创建
        String s2 = "Java";          // 引用常量池中的同一对象
        String s3 = new String("Java"); // 在堆中创建新对象
        String s4 = new String("Java"); // 在堆中创建另一个对象
        
        System.out.println("s1 == s2: " + (s1 == s2)); // true,同一常量
        System.out.println("s1 == s3: " + (s1 == s3)); // false,不同对象
        System.out.println("s3 == s4: " + (s3 == s4)); // false,不同对象
        System.out.println("s1.equals(s3): " + s1.equals(s3)); // true,内容相同
    }
}

内存结构示意图

text

栈内存:     堆内存:       字符串常量池:
s1 ──────→  对象1   ←─── "Java"
s2 ──────┘
s3 ──────→  对象2
s4 ──────→  对象3

三、字符串比较操作

3.1 比较方法详解

java

public class StringComparison {
    public static void main(String[] args) {
        // 创建测试字符串
        String str1 = new String("Hello");
        String str2 = new String("Hello");
        String str3 = new String("hello");
        String str4 = "Hello";
        String str5 = "Hello";
        
        // == 操作符比较(比较引用地址)
        System.out.println("== 操作符比较:");
        System.out.println("str1 == str2: " + (str1 == str2)); // false
        System.out.println("str4 == str5: " + (str4 == str5)); // true
        
        // equals方法比较(比较内容)
        System.out.println("\nequals方法比较:");
        System.out.println("str1.equals(str2): " + str1.equals(str2)); // true
        System.out.println("str1.equals(str3): " + str1.equals(str3)); // false
        
        // equalsIgnoreCase方法(忽略大小写)
        System.out.println("\nequalsIgnoreCase方法比较:");
        System.out.println("str1.equalsIgnoreCase(str3): " + 
                          str1.equalsIgnoreCase(str3)); // true
        
        // compareTo方法(字典序比较)
        System.out.println("\ncompareTo方法比较:");
        System.out.println(""abc".compareTo("abd"): " + 
                          "abc".compareTo("abd")); // -1
        System.out.println(""abc".compareTo("abC"): " + 
                          "abc".compareTo("abC")); // 32
        System.out.println(""abc".compareToIgnoreCase("abC"): " + 
                          "abc".compareToIgnoreCase("abC")); // 0
    }
}

四、字符串查找操作

4.1 字符和子串查找

java

public class StringSearch {
    public static void main(String[] args) {
        String text = "Hello World, Welcome to Java Programming";
        
        // charAt方法 - 获取指定位置字符
        System.out.println("charAt方法演示:");
        System.out.println("位置0的字符: " + text.charAt(0));
        System.out.println("位置6的字符: " + text.charAt(6));
        
        // 遍历所有字符
        System.out.println("\n遍历字符串:");
        for (int i = 0; i < text.length(); i++) {
            System.out.print(text.charAt(i) + " ");
        }
        System.out.println();
        
        // indexOf方法 - 查找字符或子串位置
        System.out.println("\nindexOf方法演示:");
        System.out.println("第一次出现'o'的位置: " + text.indexOf('o'));
        System.out.println("从位置5开始第一次出现'o'的位置: " + text.indexOf('o', 5));
        System.out.println("第一次出现"World"的位置: " + text.indexOf("World"));
        System.out.println("第一次出现"Java"的位置: " + text.indexOf("Java"));
        
        // lastIndexOf方法 - 从后往前查找
        System.out.println("\nlastIndexOf方法演示:");
        System.out.println("最后一次出现'o'的位置: " + text.lastIndexOf('o'));
        System.out.println("从位置20开始往前找'o'的位置: " + text.lastIndexOf('o', 20));
        System.out.println("最后一次出现"o"的位置: " + text.lastIndexOf("o"));
        
        // contains方法 - 检查是否包含子串
        System.out.println("\ncontains方法演示:");
        System.out.println("是否包含"Java": " + text.contains("Java"));
        System.out.println("是否包含"Python": " + text.contains("Python"));
        
        // startsWith和endsWith方法
        System.out.println("\nstartsWith/endsWith方法演示:");
        System.out.println("是否以"Hello"开头: " + text.startsWith("Hello"));
        System.out.println("是否以"Programming"结尾: " + text.endsWith("Programming"));
    }
}

五、字符串转换操作

5.1 类型转换详解

java

public class StringConversion {
    public static void main(String[] args) {
        // 其他类型转字符串
        System.out.println("其他类型转字符串:");
        int num = 1234;
        double decimal = 12.34;
        boolean flag = true;
        
        String str1 = String.valueOf(num);
        String str2 = String.valueOf(decimal);
        String str3 = String.valueOf(flag);
        
        System.out.println("整数转字符串: " + str1);
        System.out.println("小数转字符串: " + str2);
        System.out.println("布尔值转字符串: " + str3);
        
        // 验证确实是字符串
        System.out.println("\n字符串拼接验证:");
        System.out.println(str1 + 11); // "123411" 不是 1245
        
        // 字符串转其他类型
        System.out.println("\n字符串转其他类型:");
        int parsedInt = Integer.parseInt("1234");
        double parsedDouble = Double.parseDouble("12.34");
        boolean parsedBoolean = Boolean.parseBoolean("false");
        
        System.out.println("字符串转整数: " + (parsedInt + 11)); // 1245
        System.out.println("字符串转小数: " + parsedDouble);
        System.out.println("字符串转布尔: " + parsedBoolean);
        
        // 字符数组与字符串互转
        System.out.println("\n字符数组与字符串互转:");
        String original = "Hello World";
        char[] charArray = original.toCharArray();
        
        System.out.print("字符数组: ");
        for (char c : charArray) {
            System.out.print(c + " ");
        }
        System.out.println();
        
        String restored = new String(charArray);
        System.out.println("恢复的字符串: " + restored);
        
        // 格式化字符串
        System.out.println("\n格式化字符串:");
        String formatted = String.format("姓名: %s, 年龄: %d, 分数: %.2f", 
                                       "张三", 20, 95.5);
        System.out.println(formatted);
        
        // 自定义对象转字符串
        System.out.println("\n自定义对象转字符串:");
        Student student = new Student("李四", 22);
        String studentStr = String.valueOf(student);
        System.out.println("学生信息: " + studentStr);
    }
}

class Student {
    private String name;
    private int age;
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Student{name='" + name + "', age=" + age + "}";
    }
}

六、字符串修改操作

6.1 替换操作

java

public class StringModification {
    public static void main(String[] args) {
        String text = "Hollow Horld, Welcome to Jova Programming";
        
        System.out.println("原始字符串: " + text);
        
        // 单个字符替换
        System.out.println("替换'H'为'W': " + text.replace('H', 'W'));
        
        // 字符串替换
        System.out.println("替换"Hollow"为"Hello": " + 
                          text.replace("Hollow", "Hello"));
        
        // 替换所有匹配
        System.out.println("替换所有'o'为'0': " + text.replaceAll("o", "0"));
        
        // 使用正则表达式替换
        System.out.println("替换第一个'o'为'*': " + text.replaceFirst("o", "*"));
        
        // 正则表达式复杂替换
        String text2 = "价格: $100, $200, $300";
        System.out.println("替换美元符号: " + text2.replaceAll("\$", "¥"));
    }
}

6.2 拆分操作

java

public class StringSplit {
    public static void main(String[] args) {
        // 基本拆分
        String data = "student&0x123456&admin&0x789abc";
        String[] parts = data.split("&");
        
        System.out.println("基本拆分结果:");
        for (int i = 0; i < parts.length; i++) {
            System.out.println("部分" + (i + 1) + ": " + parts[i]);
        }
        
        // 限制拆分次数
        String[] limitedParts = data.split("&", 2);
        System.out.println("\n限制拆分次数结果:");
        for (String part : limitedParts) {
            System.out.println(part);
        }
        
        // 特殊字符拆分(需要转义)
        String ip = "192.168.1.1";
        String[] ipParts = ip.split("\.");
        System.out.println("\nIP地址拆分:");
        for (String part : ipParts) {
            System.out.println(part);
        }
        
        // 多个分隔符
        String complexData = "apple,banana;orange|grape";
        String[] fruits = complexData.split("[,;|]");
        System.out.println("\n多分隔符拆分:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        
        // CSV文件解析示例
        String csvLine = "John,Doe,30,"New York, NY",Engineer";
        String[] csvParts = csvLine.split(",(?=(?:[^"]*"[^"]*")*[^"]*$)");
        System.out.println("\nCSV解析:");
        for (String part : csvParts) {
            System.out.println(part.replace(""", ""));
        }
    }
}

6.3 截取操作

java

public class StringSubstring {
    public static void main(String[] args) {
        String text = "123425516789";
        
        System.out.println("原始字符串: " + text);
        
        // 从指定位置截取到末尾
        String sub1 = text.substring(7);
        System.out.println("从位置7截取到末尾: " + sub1);
        
        // 截取指定范围
        String sub2 = text.substring(2, 6);
        System.out.println("截取位置2到6: " + sub2);
        
        // 实际应用:提取文件名和扩展名
        String filePath = "document.pdf";
        int dotIndex = filePath.lastIndexOf('.');
        
        String fileName = filePath.substring(0, dotIndex);
        String fileExtension = filePath.substring(dotIndex + 1);
        
        System.out.println("\n文件路径解析:");
        System.out.println("文件名: " + fileName);
        System.out.println("扩展名: " + fileExtension);
        
        // 提取域名
        String url = "https://www.example.com/path/to/page";
        int start = url.indexOf("://") + 3;
        int end = url.indexOf('/', start);
        String domain = (end == -1) ? url.substring(start) : url.substring(start, end);
        
        System.out.println("域名: " + domain);
    }
}

七、其他常用操作

7.1 字符串工具方法

java

public class StringUtilities {
    public static void main(String[] args) {
        String text = "   Hello World   ";
        
        System.out.println("原始字符串: '" + text + "'");
        
        // 大小写转换
        System.out.println("转换为大写: '" + text.toUpperCase() + "'");
        System.out.println("转换为小写: '" + text.toLowerCase() + "'");
        
        // 去除空白字符
        System.out.println("去除首尾空格: '" + text.trim() + "'");
        
        // 判断空字符串
        String emptyStr = "";
        String nullStr = null;
        String spaceStr = "   ";
        
        System.out.println("\n空字符串检查:");
        System.out.println("emptyStr为空: " + emptyStr.isEmpty());
        System.out.println("spaceStr.trim()为空: " + spaceStr.trim().isEmpty());
        // System.out.println("nullStr为空: " + nullStr.isEmpty()); // NullPointerException
        
        // 使用安全检查
        System.out.println("安全检查 - emptyStr: " + isNullOrEmpty(emptyStr));
        System.out.println("安全检查 - nullStr: " + isNullOrEmpty(nullStr));
        System.out.println("安全检查 - spaceStr: " + isNullOrEmpty(spaceStr));
        System.out.println("安全检查 - text: " + isNullOrEmpty(text));
        
        // 字符串连接
        String[] words = {"Java", "Python", "C++", "JavaScript"};
        String joined = String.join(" | ", words);
        System.out.println("\n字符串连接: " + joined);
    }
    
    // 安全的空字符串检查方法
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }
}

八、字符串不可变性与性能优化

8.1 不可变性原理

java

public class StringImmutability {
    public static void main(String[] args) {
        // 展示字符串不可变性
        String str1 = "Hello";
        String str2 = str1;  // str2指向同一对象
        
        System.out.println("修改前:");
        System.out.println("str1: " + str1 + " | hashCode: " + System.identityHashCode(str1));
        System.out.println("str2: " + str2 + " | hashCode: " + System.identityHashCode(str2));
        
        str1 = str1 + " World";  // 创建新对象
        
        System.out.println("\n修改后:");
        System.out.println("str1: " + str1 + " | hashCode: " + System.identityHashCode(str1));
        System.out.println("str2: " + str2 + " | hashCode: " + System.identityHashCode(str2));
        
        // 性能问题演示
        System.out.println("\n字符串拼接性能问题:");
        long startTime = System.currentTimeMillis();
        
        String result = "";
        for (int i = 0; i < 10000; i++) {
            result += i;  // 每次循环创建新String对象
        }
        
        long endTime = System.currentTimeMillis();
        System.out.println("直接拼接耗时: " + (endTime - startTime) + "ms");
    }
}

8.2 使用StringBuilder优化

java

public class StringBuilderDemo {
    public static void main(String[] args) {
        // StringBuilder用于可变字符串操作
        System.out.println("StringBuilder性能优化:");
        long startTime = System.currentTimeMillis();
        
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            sb.append(i);  // 不会创建新对象
        }
        String result = sb.toString();
        
        long endTime = System.currentTimeMillis();
        System.out.println("StringBuilder拼接耗时: " + (endTime - startTime) + "ms");
        
        // StringBuilder常用方法
        StringBuilder builder = new StringBuilder("Hello");
        builder.append(" World")          // 追加
               .insert(5, ",")           // 插入
               .replace(6, 11, "Java")   // 替换
               .delete(10, 12);          // 删除
        
        System.out.println("最终结果: " + builder.toString());
        System.out.println("反转: " + builder.reverse().toString());
    }
}

九、最佳实践总结

核心要点

  1. 字符串创建:优先使用字面量方式,避免不必要的对象创建
  2. 字符串比较:使用equals()比较内容,==比较引用
  3. 字符串操作:大量修改时使用StringBuilder
  4. 内存优化:理解字符串常量池机制

性能建议

java

public class StringBestPractices {
    public static void main(String[] args) {
        // 1. 使用StringBuilder进行大量拼接
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("SELECT * FROM users ")
                  .append("WHERE age > 18 ")
                  .append("AND status = 'active' ")
                  .append("ORDER BY name");
        String sql = sqlBuilder.toString();
        
        // 2. 使用equalsIgnoreCase进行不区分大小写比较
        String input = "ADMIN";
        if ("admin".equalsIgnoreCase(input)) {
            System.out.println("权限验证通过");
        }
        
        // 3. 使用String.join连接字符串数组
        String[] tags = {"java", "programming", "tutorial"};
        String tagString = String.join(", ", tags);
        System.out.println("标签: " + tagString);
        
        // 4. 使用String.format进行复杂格式化
        String message = String.format("用户%s在%s登录,IP地址:%s", 
                                     "张三", "2024-01-15", "192.168.1.100");
        System.out.println(message);
    }
}

String类是Java中最常用且最重要的类之一,深入理解其特性和使用方法对于编写高效的Java程序至关重要。