《深入理解Java字符串:从基础到高级特性》
目录
一、String类概述
String的基本特性
二、String的创建方式
1. 字面量方式(推荐)
2. new关键字方式
两种方式的区别
三、字符串不可变性
不可变性的含义
不可变性的优势
四、字符串常量池
字符串池工作原理
intern()方法
五、String常用API
1. 字符串比较
2. 字符串查找
3. 字符串操作
六、StringBuilder和StringBuffer
1. StringBuilder(非线程安全,性能更高)
2. StringBuffer(线程安全)
性能对比案例
七、字符串与编码
字符编码转换
八、字符串格式化
1. String.format()
2. 格式化符号
九、字符串与正则表达式
常用正则方法
十、字符串综合案例
案例1:字符串反转
案例2:字符串统计
十一、字符串最佳实践
十二、String与包装类的结合案例
一、String类概述
String是Java中最常用的类之一,用于表示和操作字符串。Java中的字符串是不可变的(immutable),这意味着一旦创建,其内容就不能被改变。
String的基本特性
-
不可变性:String对象一旦创建就不能修改
-
存储在字符串常量池:字符串字面量存储在特殊的堆内存区域
-
支持Unicode:Java字符串内部使用UTF-16编码
-
丰富的API:提供了大量字符串操作方法
二、String的创建方式
1. 字面量方式(推荐)
String str1 = "Hello World"; // 存储在字符串常量池
2. new关键字方式
String str2 = new String("Hello World"); // 在堆中创建新对象
两种方式的区别
String a = "hello"; String b = "hello"; String c = new String("hello"); String d = new String("hello");System.out.println(a == b); // true,指向常量池同一对象 System.out.println(a == c); // false,不同对象 System.out.println(c == d); // false,两个不同的堆对象
三、字符串不可变性
不可变性的含义
String s = "hello"; s.concat(" world"); // 返回新字符串,原字符串不变 System.out.println(s); // 输出"hello"s = s.concat(" world"); // 重新赋值 System.out.println(s); // 输出"hello world"
不可变性的优势
-
安全性:字符串作为参数传递时不会被意外修改
-
线程安全:无需同步即可在多线程中使用
-
缓存哈希值:String的hashCode()可以缓存,提高性能
-
字符串池优化:允许多个引用共享相同字符串
四、字符串常量池
字符串常量池(String Pool)是Java堆内存中的特殊存储区域,用于存储字符串字面量。
字符串池工作原理
String s1 = "Java"; String s2 = "Java"; String s3 = new String("Java");System.out.println(s1 == s2); // true System.out.println(s1 == s3); // falses3 = s3.intern(); // 将字符串放入池中(如果池中已有则返回池中引用) System.out.println(s1 == s3); // true
intern()方法
String str1 = new String("hello").intern(); String str2 = "hello"; System.out.println(str1 == str2); // true
五、String常用API
1. 字符串比较
String a = "hello"; String b = "HELLO";System.out.println(a.equals(b)); // false System.out.println(a.equalsIgnoreCase(b)); // true System.out.println(a.compareTo(b)); // 正数,表示a>b
2. 字符串查找
String str = "Java Programming";System.out.println(str.contains("Pro")); // true System.out.println(str.indexOf("a")); // 1 System.out.println(str.lastIndexOf("a")); // 10 System.out.println(str.startsWith("Java")); // true System.out.println(str.endsWith("ing")); // true
3. 字符串操作
String original = " Hello World ";// 去除前后空格 String trimmed = original.trim(); System.out.println(trimmed); // "Hello World"// 替换字符 String replaced = original.replace('l', 'L'); System.out.println(replaced); // " HeLLo WorLd "// 分割字符串 String[] parts = "one,two,three".split(","); System.out.println(Arrays.toString(parts)); // [one, two, three]// 子字符串 String sub = original.substring(4, 9); System.out.println(sub); // "ello "
六、StringBuilder和StringBuffer
由于String的不可变性,频繁修改字符串时会产生大量中间对象。StringBuilder和StringBuffer提供了可变的字符串操作。
1. StringBuilder(非线程安全,性能更高)
StringBuilder sb = new StringBuilder(); sb.append("Hello"); sb.append(" "); sb.append("World"); String result = sb.toString(); // "Hello World"
2. StringBuffer(线程安全)
StringBuffer sbf = new StringBuffer(); sbf.append("Hello"); sbf.append(" "); sbf.append("World"); String result = sbf.toString(); // "Hello World"
性能对比案例
public class StringPerformance {public static void main(String[] args) {// 使用String拼接long startTime = System.currentTimeMillis();String result = "";for (int i = 0; i < 10000; i++) {result += i;}long endTime = System.currentTimeMillis();System.out.println("String拼接耗时: " + (endTime - startTime) + "ms");// 使用StringBuilder拼接startTime = System.currentTimeMillis();StringBuilder sb = new StringBuilder();for (int i = 0; i < 10000; i++) {sb.append(i);}endTime = System.currentTimeMillis();System.out.println("StringBuilder拼接耗时: " + (endTime - startTime) + "ms");} }
七、字符串与编码
字符编码转换
String str = "你好,世界";try {// 字符串转字节数组byte[] utf8Bytes = str.getBytes("UTF-8");byte[] gbkBytes = str.getBytes("GBK");// 字节数组转字符串String utf8Str = new String(utf8Bytes, "UTF-8");String gbkStr = new String(gbkBytes, "GBK");System.out.println("UTF-8编码长度: " + utf8Bytes.length);System.out.println("GBK编码长度: " + gbkBytes.length); } catch (UnsupportedEncodingException e) {e.printStackTrace(); }结果:
UTF-8编码长度: 15
GBK编码长度: 10
八、字符串格式化
1. String.format()
String name = "Alice"; int age = 25; double score = 95.5;String info = String.format("姓名: %s, 年龄: %d, 成绩: %.1f", name, age, score); System.out.println(info); // 姓名: Alice, 年龄: 25, 成绩: 95.5
2. 格式化符号
符号 | 说明 |
---|---|
%s | 字符串 |
%d | 十进制整数 |
%f | 浮点数 |
%n | 换行符 |
%% | 百分号 |
九、字符串与正则表达式
常用正则方法
String text = "我的电话是123-4567-8910,邮箱是example@email.com";// 检查匹配 boolean hasPhone = text.matches(".*\\d{3}-\\d{4}-\\d{4}.*"); System.out.println("包含电话号码: " + hasPhone); // true// 提取匹配 Pattern pattern = Pattern.compile("\\w+@\\w+\\.\\w+"); Matcher matcher = pattern.matcher(text); while (matcher.find()) {System.out.println("找到邮箱: " + matcher.group()); // example@email.com }// 替换 String replaced = text.replaceAll("\\d", "*"); System.out.println(replaced); // 我的电话是***-****-****,邮箱是example@email.com
十、字符串综合案例
案例1:字符串反转
public class StringReverse {// 方法1:使用StringBuilderpublic static String reverseWithStringBuilder(String input) {return new StringBuilder(input).reverse().toString();}// 方法2:使用字符数组public static String reverseWithCharArray(String input) {char[] chars = input.toCharArray();int left = 0, right = chars.length - 1;while (left < right) {char temp = chars[left];chars[left] = chars[right];chars[right] = temp;left++;right--;}return new String(chars);}public static void main(String[] args) {String original = "abcdefg";System.out.println("StringBuilder反转: " + reverseWithStringBuilder(original));System.out.println("字符数组反转: " + reverseWithCharArray(original));} }
案例2:字符串统计
public class StringStatistics {public static void main(String[] args) {String text = "Java是一种广泛使用的编程语言,由Sun Microsystems于1995年发布。";// 统计字符数System.out.println("字符数: " + text.length());// 统计汉字数int chineseCount = 0;for (int i = 0; i < text.length(); i++) {if (isChinese(text.charAt(i))) {chineseCount++;}}System.out.println("汉字数: " + chineseCount);// 统计单词数(简单版)String englishText = "Java is a popular programming language";String[] words = englishText.split("\\s+");System.out.println("单词数: " + words.length);}private static boolean isChinese(char c) {Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION;} }
十一、字符串最佳实践
-
优先使用字符串字面量:比new String()更高效
-
避免频繁拼接字符串:使用StringBuilder/StringBuffer
-
使用equals()比较内容:而非==运算符
-
注意字符串编码:特别是在I/O操作时
-
合理使用intern():大量重复字符串可考虑使用,但不要滥用
-
预编译正则表达式:如需重复使用
十二、String与包装类的结合案例
public class StringAndWrapper {public static void main(String[] args) {// String与基本类型/包装类转换String numStr = "123";// String转int/Integerint primitiveInt = Integer.parseInt(numStr);Integer wrapperInt = Integer.valueOf(numStr);// int/Integer转StringString str1 = String.valueOf(primitiveInt);String str2 = wrapperInt.toString();System.out.println("原始字符串: " + numStr);System.out.println("转为int: " + primitiveInt);System.out.println("转为Integer: " + wrapperInt);System.out.println("转回String(1): " + str1);System.out.println("转回String(2): " + str2);// 特殊格式转换String doubleStr = "3.1415926";double d = Double.parseDouble(doubleStr);System.out.printf("圆周率: %.2f\n", d);// 进制转换String binaryStr = "1010";int decimal = Integer.parseInt(binaryStr, 2);System.out.println(binaryStr + "的十进制值: " + decimal);} }