Stringインスタンスのパンを焼こう
本日のコードはこちら。簡略型で行きますが
String a = "abc";
String b = new String("abc");
では、次の演算は、true、false、どちらになるでしょう。
このとき、Java人には常識かもですが、「==」という記号は、単に同値なのではなく同じインスタンスを指しているかどうかを判定することに注意してください。
a === b;
はい、こちらは先ほど述べた理由で、falseになりますね。では次です。
a == b.intern()
正解は、、、trueです。なぜでしょう。
答えは「パンをおいておく場所」にあります。
String a = "abc"
このコードは、"abc"という「リテラル」を用いて、String型のインスタンスを生成、初期化しています。
このとき、インスタンスは コンスタントプール というメモリに保存されます。
僕は、 Aくんが、abcパンを焼いて(インスタンスを生成、初期化)、コンスタントプール棚に置き、それをじっと見る(参照) というイメージを思い浮かべました。
コンスタントプール棚に置かれたパン(インスタンス)は、別の場面で同じ値(例えば"abc")を参照したいときに、使い回されます。「プール」なので、みんなが繰り返し入るイメージですかね。
一方で
String b = new String("abc")
こちらのコードは、明示的にString型のクラスをnewして、インスタンスを生成し、コンストラクタを用いて初期化しています。
このとき、インスタンスは、ヒープ領域というメモリに保存されます。
Bくんは、同じリテラルを持つコンスタントプール棚のパンを再利用できるのに、それには目もくれず、新しくabcパンを焼いて、ヒープ棚に置いたんですね。
AくんとBくんは、置かれている場所の違う、 異なるパン(インスタンス)を見ている(参照している) んですね。
だから一つ目のコードはfalseを示します。違うパンを見ているんだから、当然ですね。
そして、 Stringクラスが持つinternメソッド を用いると、明示的にコンスタントプールのインスタンスを参照させることができるんです。つまり
a == b.intern()
元々ヒープ棚のパンを見ていたBくんが、"インターンくん"に、「Bくん、コンスタントプール棚の方が美味しそうだよ、そっちを見なよ」って言われるんですね。
Bくん、「そういうならそっちを見よ」と言って、コンスタントプール棚のパンを見始めるんですね。「B.intern()」
同じ棚のパンを見ているので、二つ目のコードは、trueを示すんですね。
最近インスタンスを生成、初期化して参照するのを、「パン🍞を焼いてそれをじっと見る👀」っていう謎の例えにハマってるんですよね。流行んないかな、これ。
Discussion