Stringはプログラムを書く上で避けて通れない変数の一種です。
文字列の参照は、ユーザー名やパスワードなど、さまざまな属性を保存するために使用されます。
JavaではStringオブジェクトは実はイミュータブル(不変)です。イミュータブルとは、簡単に言えば変更できない、あるいは変更させないことを意味します。
Stringオブジェクトが作成されると、そのデータや状態を変更することはできず、新しいStringオブジェクトが作成されます。
普段String型を使っていると、当たり前のように代入し文字列の変更を行うので、こういった意識はない人が多いと思います。
以下に示す例で、イミュータブルの概念を理解してみましょう。
class Testimmutablestring{ public static void main(String args[]){ String s="Sachin"; s.concat(" Tendulkar");//concat() メソッドは、文字列を末尾に追加します。 System.out.println(s);//Sachin と表示されます。文字列は不変のオブジェクトだからです } } //Sachin
上の例だと2つのオブジェクトが作成され、s参照変数はまだ "Sachin "を参照しており、"Sachin Tendulkar "を参照していません。
しかし、下の例のように、明示的にs参照変数に代入すると、"Sachin Tendulkar" オブジェクトを参照するようになります。
class Testimmutablestring1{ public static void main(String args[]){ String s="Sachin"; s=s.concat(" Tendulkar"); System.out.println(s); } } //Sachin Tendulkar
ここで注意すべき点は、Stringオブジェクトは不変ですが、その参照変数は不変ではないということです。そのため、上記の例では、新しく形成されたStringオブジェクトを参照されています。
例えば4つの参照変数があり、すべてが1つのオブジェクト "Sachin "を参照しているとします。この時、1つの参照変数がオブジェクトの値を変更すると、すべての参照変数に影響します。
Javaの文字列String型の比較がequalsで行うように言われるのは、上記のような理由からです。
なぜStringがイミュータブルなのか?
Javaの作成者であるJamesGoslingは、インタビューで「いつイミュータブルを使うべきか」と聞かれ「できる限りimmutableを使いたい」と答えたことがあります。
さらに、キャッシュ、セキュリティ、レプリケーションを使わない再利用のしやすさなど、不変性がもたらす特徴を挙げて、その論拠を示していました。
String型は、どのプログラムでもよく使われるオブジェクトの1つです。
JavaではStringはfinalでimmutableなクラスであり、特殊なクラスです。継承することができず、一度作成したオブジェクトを変更することはできません。
以下は、Stringの特徴や、Stringが不変である理由を理解するのに役立つ話になります。
ClassLoader
JavaにおけるClassLoaderは、引数としてStringオブジェクトを使用します。
ここで、Stringオブジェクトが変更可能であった場合、値が変更され、ロードされるはずのクラスが異なる可能性があることを考えましょう。
このような誤解を避けるために、Stringはimmutableであるべきです。
Thread Safe
不変性は暗黙的にStringのスレッドセーフを実現します。
Stringオブジェクトは不変なので、複数のスレッドでオブジェクトを共有する際に必要な同期の世話は不要になります。
Security
クラスの読み込みで見たように、イミュータブルなStringオブジェクトは正しいクラスを読み込むことで、さらなるエラーを回避します。
これは、アプリケーションプログラムをより安全にすることにつながります。
銀行のソフトウェアの例で考えてみましょう。Stringオブジェクトは不変なので、ユーザ名とパスワードは侵入者によって変更されることはありません。これは、アプリケーションの安全性をより高めることができます。
Heap Space
Stringの不変性は、ヒープメモリの使用量を最小限に抑えるのに役立ちます。
新しいStringオブジェクトを宣言しようとすると、JVMはその値がStringプールにすでに存在するかどうかをチェックします。
もし存在すれば、同じ値が新しいオブジェクトに割り当てられます。この機能により、Javaはヒープ空間を効率的に使用することができます。