str1.intern() == str1居然是false?面试被问懵了!

我有一个特别好的朋友,就叫小烦吧,今天请假出去面试,然后碰了一鼻子灰,回来之后死皮赖脸的让我把这些内容记录然后分享出来,我拗不过它,只好答应下来。

无中生友

事情的经过是这样的。

我那个最好的朋友小烦给经理请假,理由是嘴角一个口疮长在了痔上,没办法说话要在家静养一天。经理虽然满头问号,但还是批准了。

然后小烦就去了某某跳动去面试。

刚一坐下,对面的面试官脑门一闪,把电脑扭到小烦面前:“这段代码的执行结果是什么?”

小烦定睛一看:

String str1 = new StringBuilder().append("ja").append("va").toString();
System.out.println(str1.intern() == str1);

String str2 = new StringBuilder().append("Solid").append("Snaker").toString();
System.out.println(str2.intern() == str2);

这种难度的小问题还能难住我?然后信心百倍的给出答案:

都是true!

面试官摇了摇头,点了run();

false
true

小烦一脸懵逼:what?这俩有啥不一样吗?

面试继续进行,小烦满脑子都是问号,心思没放在面试上,自然答得一塌糊涂。

随着面试官的一句“出门左转是电梯”,这次面试也划上了尾声。小烦二话没说冲回家,打开电脑面向百度编程一顿搜索,然后又查阅了相关书籍,终于找到了原因所在。

“java”这个字符串有问题!

首先我们来看一眼intern()这个方法:

/**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     * @jls 3.10.5 String Literals
     */
    public native String intern();

主要注意这一段:

When the intern method is invoked, if the pool already contains a string equal to this {@code String} object as determined by the {@link #equals(Object)} method, then the string from the pool is returned. Otherwise, this {@code String} object is added to the pool and a reference to this {@code String} object is returned.

翻译过来的意思是:

当intern方法被调用时,如果常量池中已经包含了一个字符串,该字符串等于这个对象,那么池中的字符串将被返回。否则,该对象将被添加到池中,并返回对该对象的引用。

其实,intern()是一个Native方法,底层调用C++的 StringTable::intern方法实现。当通过语句str.intern()调用intern()方法后,JVM 就会在当前类的常量池中查找是否存在与str等值的String,若存在则直接返回常量池中相应Strnig的引用;若不存在,则会在常量池中创建一个等值的String,然后返回这个String在常量池中的引用。因此,只要是等值的String对象,使用intern()方法返回的都是常量池中同一个String引用,所以,这些等值的String对象通过intern()后使用==是可以匹配的。

其实严格来说,上面那段代码在JDK1.6中,会得到两个false;而在JDK1.7及之后中运行,则会得到一个false和一个true。

《深入理解java虚拟机》这本书上出现了同样的题目:

《深入理解java虚拟机》

而答案如下:

《深入理解java虚拟机》

可是问题又来了,哪儿出现的“java”这个字符串呢?明明我只运行了一个main方法啊?

答案就是:

sun.misc.Version类!

sun.misc.Version 类会在JDK类库的初始化过程中被加载并初始化,而在初始化时它需要对静态常量字段根据指定的常量值(ConstantValue)做默认初始化,此时被 sun.misc.Version.launcher 静态常量字段所引用的"java"字符串字面量就被intern到HotSpot VM的字符串常量池——StringTable里了。

private static final String launcher_name = "java";

private static final String launcher_name = "@@launcher_name@@";

感兴趣的同学可以自己去看看OpenJDK,看一下这个类里面的东西。

这下答案水落石出了,小烦高兴的瞬间啃了两个香辣猪肘子~~~

然后去了肛肠科。

第二天去到公司,经理看到小烦捂着屁股站不起来的样子,脑海里的问号又多了几个。


因为你会,所以你不会。

我是Solid-Snaker,我们下期再见。

megumi

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值