在Java开发中,字符串是比较操作中最常见的场景之一,无论是用户登录时的密码校验、数据排序时的字典序比较,还是文本处理中的大小写匹配,字符串比较都是绕不开的基础技能,很多初学者(甚至部分有经验的开发者)对字符串比较的底层逻辑和最佳实践仍存在模糊认知,本文将结合极客在线教育的实战教学经验,从基础到进阶,系统梳理Java中字符串比较的各种方法、使用场景及避坑指南。
为什么字符串比较容易“踩坑”?——先理解字符串的本质
要掌握字符串比较,首先要明白Java中字符串的两大核心特性:不可变性(Immutable)和常量池机制。
String类被设计为不可变,这意味着一旦字符串被创建,其内容就不能修改。String s = "hello"和String t = new String("hello")相同,但它们的内存地址可能不同(t会在堆中新建对象,而s可能指向常量池中的字符串),这种特性直接影响了字符串比较的结果——比较的是“内容”还是“地址”?
字符串比较的“两大阵营”:“==” vs “equals()”
“==”:比较的是内存地址,不是内容!
是Java中的关系运算符,用于比较两个变量的内存地址是否相同,对于字符串来说,只有当两个字符串变量指向同一个内存对象时,才返回true。
String s1 = "hello"; // 常量池中创建
String s2 = "hello"; // 直接引用常量池中的"hello"
String s3 = new String("hello"); // 堆中新建对象,内容与s1相同
String s4 = s1; // 与s1指向同一对象
System.out.println(s1 == s2); // true(常量池中同一个对象)
System.out.println(s1 == s3); // false(s1在常量池,s3在堆中)
System.out.println(s1 == s4); // true(s4是s1的引用)
极客在线教育提醒:绝对不要用比较字符串内容! 这是新手最常犯的错误,用户输入的密码"123"和预设密码"123"相同,也可能返回false(因为new String()会创建新对象)。
equals():比较字符串内容是否相同
String类重写了Object类的equals()方法,专门用于比较两个字符串的是否一致(逐字符比较,区分大小写)。
String s1 = "hello";
String s2 = "Hello";
String s3 = new String("hello");
System.out.println(s1.equals(s2)); // false('h'和'H'大小写不同)
System.out.println(s1.equals(s3)); // true(内容相同,忽略地址)
核心逻辑:equals()会逐个字符比较Unicode值,只有所有字符都相同(包括大小写),才返回true。
equalsIgnoreCase():忽略大小写的内容比较
如果需要比较字符串内容但忽略大小写(例如用户名不区分大小写登录),可以使用equalsIgnoreCase()。
String username1 = "Geek"; String username2 = "geek"; String username3 = "GEEK"; System.out.println(username1.equalsIgnoreCase(username2)); // true System.out.println(username1.equalsIgnoreCase(username3)); // true
进阶比较:字典序与“差值”比较——compareTo()系列
除了简单的“相同/不同”,有时我们需要对字符串进行排序或比较大小(例如按字典序排列单词),这时就需要用到compareTo()方法。
compareTo():字典序比较,返回差值
compareTo()按字典序(lexicographical order)比较两个字符串,返回一个整数值:
- 返回
0:两个字符串内容完全相同(相当于equals()返回true); - 返回负数:调用字符串的字典序小于参数字符串;
- 返回正数:调用字符串的字典序大于参数字符串。
字典序规则:从左到右逐个字符比较Unicode值,第一个不同字符的差值即为结果,如果其中一个字符串是另一个的前缀,则较短的字符串更小。
String s1 = "apple"; String s2 = "banana"; String s3 = "apple"; String s4 = "applet"; System.out.println(s1.compareTo(s2)); // -1('a'的Unicode是97,'b'是98,97-98=-1) System.out.println(s2.compareTo(s1)); // 1 System.out.println(s1.compareTo(s3)); // 0 System.out.println(s1.compareTo(s4)); // -4("apple"比"applet"短4个字符)
compareToIgnoreCase():忽略大小写的字典序比较
类似equalsIgnoreCase(),compareToIgnoreCase()在比较时忽略大小写,返回值规则与compareTo()一致。
String s1 = "Geek"; String s2 = "geek"; String s3 = "Google"; System.out.println(s1.compareToIgnoreCase(s2)); // 0(忽略大小写后内容相同) System.out.println(s1.compareToIgnoreCase(s3)); // 6('G'和'g'的Unicode相同,'e'和'o'差6)
安全比较:Objects.equals()与Objects.requireNonNull()
在实际开发中,字符串变量可能为null,直接调用equals()会导致NullPointerException,Java 7引入的Objects类提供了更安全的比较方法。
Objects.equals(a, b):安全的“内容比较”
Objects.equals()会先检查两个参数是否为null:
- 如果
a和b都为null,返回true; - 如果其中一个为
null,返回false; - 否则调用
a.equals(b)。
String s1 = null; String s2 = "hello"; String s3 = null; System.out.println(s1.equals(s2)); // NPE! System.out.println(Objects.equals(s






