JavaのStringはimmutable

Java

[Java] Stringはimmutable

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はヒープ空間を効率的に使用することができます。

  • この記事を書いた人

朝倉卍丸

シングルモルトスコッチなどのお土産を持ってきた人を助けるのが好きです。サービスの分割が重要ですが、まあ昔ながらの方法でやりたいこともありますよね。

よく読まれている記事

条件の0=0は全てが正であるを意味するSQL 1

SQLの条件に0=0のような記述を見かけます。 変わった書き方の条件ですが、これは「全てが正である」事を意味しており、結合条件の場合はCROSS JOINと同じです。 下記の例で言えば、結合するsub ...

DISTINCTを使わないで重複排除を考えるSQL 2

SQLのDISTINCTはEXISTSとかGROUP BYでなんとかする事もできます。 DISTINCTは暗黙的なソートがされますが、何のDBを使うにせよ過去のバージョンならともかく、最近のバージョン ...

RFC 5322に準拠させた正規表現言語別 3

RFC5322で定義されている正規表現を、各言語の正規表現に変化させた形になります。 完全な電子メール正規表現は存在しないので、結局のところ何かの公式基準に従っていたとしても、自分が携わるサービスのル ...

-Java