String str1 = new StringBuilder("hel").append("lo").toString();
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str1.intern() == str1); // true
System.out.println(str2.intern() == str2); // false
百思不得琦姐,为什么这个输出一个是 true,一个是 false ?
1
zxyroy 2017-09-25 11:33:14 +08:00
貌似和 string 长度有关,具体的我一时间查不到
|
2
rozbo 2017-09-25 11:44:19 +08:00
很简单因为`java`这个字符串之前被初始化过。
而另外一个没有。。 |
3
hcymk2 2017-09-25 11:57:19 +08:00
运行环境也不说个。
|
4
yankebupt 2017-09-25 11:59:43 +08:00
猜测有可能是因为"java"因为常用所以池中已有,append 出来的那个并不是第一个生成的所以 intern 不能指向自身...
据说不是纯引号的 literal 字符串用==会比较 reference 而不是 intern 的值,要比较值需要用.equals.... 是这样么. |
5
CallFold 2017-09-25 12:00:26 +08:00
常量池
|
6
lzx801 2017-09-25 12:01:19 +08:00
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
|
7
ZiLong OP @rozbo `java` 是被加载到 String 的字符串常量池了。但是 toString 不是返回一个新的 String 对象么?怎么会相等
|
8
yinheli 2017-09-25 12:18:24 +08:00 2
推荐书籍: 《深入理解:java 虚拟机》
intern 不同的虚拟机可能实现不同,HotSpot ( oracle jdk,openjdk )中不同的版本也有差别。 你应该用的是 jdk 7 及以上版本。 jdk7 开始,不再复制 string 实例到永久代,只是在常量池记录首次出现的实例引用,它返回的是首次创建实例的引用。 java 这个字符串比较特殊,你没写但是其他的地方也用到过。它已经在常量池(引用)里了。 |
9
adslxyz 2017-09-25 12:51:20 +08:00 4
其实这段代码的结果在不同的虚拟机实现上可能是不同的。
比如在 Oracle JDK8 中,是 true,false. 而在 OpenJDK8 中,就是 true,true. 具体原因可以参看 Oracle JDK8 的代码: 路径:./jdk/src/share/classes/sun/misc/Version.java.template 其中: ``` private static final String launcher_name = "@@launcher_name@@"; ``` 这个 @@launcher_name@@是模版占位符,会被替换为配置文件里指定的值。 如果是 Oracle JDK8,LAUNCHER_NAME=java 如果是 OpenJDK8 的话,LAUNCHER_NAME=openjdk 所以 Oracle JDK8 在初始化 sun.misc.Version 类的时候会将"java"给 intern。 同理,OpenJDK8 则会将"openjdk"给 intern。 |
10
SuperMild 2017-09-25 13:23:56 +08:00
google java string intern,前面几个连接就把这个问题说得不能更清楚了,基础技术问题为什么不 google 呢。
|
11
ZiLong OP |
14
shard 2017-09-25 16:49:33 +08:00
@ZiLong #13
我来教你一个方法: dump 你的堆; 下载 Eclipse Memory Analyzer ; 导入你 dump 文件; 然后 oql 搜索 select * from java.lang.String s where s.toString() = "java",在结果中 list incoming object 大概这样。 |
16
ZiLong OP @hubert3 虽然永久代是 Java8 移除的,但是在 Java 7 中,常量池就被移出了永久代,参见官方说明: [http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html]( http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html)
``` Area: HotSpot Synopsis: In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences. RFE: 6962931 ``` |