使用字符串的==运算符
下面的代码不应该打印“Bye”,因为==运算符用于比较引用,但奇怪的是,仍然会打印“Bye”。 为什么会这样? 我使用Netbeans 6.9.1作为IDE。
public class Test { public static void main(String [] args) { String test ="Hi"; if(test=="Hi"){ System.out.println("Bye"); } } }
这种行为是因为实习 。 String#intern
的文档中描述了这种行为(包括为什么它出现在你的代码中,即使你从不调用String#intern
):
最初为空的字符串池由
String
类私有维护。调用
intern
方法时,如果池已经包含等于此String
对象的字符串equals(Object)
由equals(Object)
方法确定equals(Object)
,则返回池中的字符串。 否则,将此String
对象添加到池中,并返回对此String
对象的引用。因此,对于任何两个字符串
s
和t
,当且仅当s.equals(t)
为真时,s.intern() == t.intern()
才为真。所有文字字符串和字符串值常量表达式都是实体。 字符串文字在Java语言规范的 §3.10.5中定义。
例如:
public class Test { private String s1 = "Hi"; public static void main(String [] args) { new Test().test(); System.exit(0); } public void test() { String s2 ="Hi"; String s3; System.out.println("[statics] s2 == s1? " + (s2 == s1)); s3 = "H" + part2(); System.out.println("[before interning] s3 == s1? " + (s3 == s1)); s3 = s3.intern(); System.out.println("[after interning] s3 == s1? " + (s3 == s1)); System.exit(0); } protected String part2() { return "i"; } }
输出:
[静态] s2 == s1? 真正 [实习前] s3 == s1? 假 [实习后] s3 == s1? 真正
走过那个:
- 分配给
s1
的文字会自动实现,因此s1
最终会引用池中的字符串。 - 分配给
s2
的文字也是自动实习的,因此s2
最终指向s1
指向的相同实例。 这很好,即使代码的两位代码可能彼此完全不知道,因为Java的String
实例是不可变的 。 你无法改变它们。 您可以使用类似toLowerCase
方法来获取带有更改的新字符串,但是调用toLowerCase
(等)的原始字符串保持不变。 因此,可以安全地在不相关的代码之间共享它们。 - 我们通过运行时操作创建一个新的
String
实例。 即使新实例与实习者具有相同的字符序列,它也是一个单独的实例。 运行时不会自动生成动态创建的字符串,因为涉及成本:在池中查找字符串的工作。 (编译时,编译器可以将成本转嫁给自己。)所以现在我们有两个实例,一个是s1
和s2
指向的,一个是s3
指向的。 所以代码显示s3 != s1
。 - 然后我们明确实习
s3
。 也许这是我们计划长期坚持的大字符串,我们认为它可能会在其他地方重复。 因此,我们接受实习的工作,以换取潜在的内存节省。 由于按定义实习意味着我们可能会返回一个新的引用,我们将结果分配回s3
。 - 我们可以看到,确实,
s3
现在指向同一个实例s1
和s2
指向。
硬编码字符串被编译到JVM的字符串表中,字符串表包含唯一的字符串 – 即编译器只存储一个“Hi”副本,因此您要比较同一个对象 ,因此==
有效。
如果你实际使用构造函数创建一个新的String,比如new String("Hi")
,你将得到一个不同的对象。
java中有一个String缓存。 在这种情况下,从具有相同引用的高速缓存返回相同的对象。
主要原因是因为从String Pool
拾取了"Hi"
。 不可变对象必须具有某种缓存,以便它可以更好地执行。 所以String
类是不可变的,它使用String Pool
进行基本缓存。
在这种情况下, "Hi"
位于String池中,所有值为"Hi"
的String将具有相同的String Pool引用。
- 为什么不使用.NET样式的委托而不是Java中的闭包?
- 在创建资源路径时从ZipFileSystemProvider获取FileSystemNotFoundException
- 在JSF / JSP EL和Javascript中连接字符串
- 当域名具有连字符时,电子邮件地址validation将失败
- Common Lisp有类似java的Set Interface /实现类吗?
- javax.security.cert.X509Certificate vs java.security.cert.X509Certificate?
- 在Java中将Chars转换为Ints
- 需要帮助java web app设计来执行后台任务
- 如何在JTable列中只选择一个复选框