1前書き

Javaでは、文字列は不変です。インタビューでかなり一般的になっている明白な質問は、「なぜ文字列はJavaでは不変として設計されているのか」です。

Javaの作成者であるJames Goslingは、いつ不変のものを使うべきかhttps://www.artima.com/intv/gosling313.html[かつてのインタビューで尋ねられました]について、彼は答えました:

私ができるときはいつでも私は不変のものを使うでしょう。

彼はさらに、キャッシング、セキュリティ、複製なしでの簡単な再利用など、不変性が提供する機能について述べた彼の主張を支持しています

このチュートリアルでは、Java言語設計者がなぜ

String

を不変にすることにしたのかをさらに詳しく説明します。

=== 2.不変オブジェクトとは何ですか?

不変オブジェクトは、完全に作成された後も内部状態が一定のままであるオブジェクトです。つまり、いったんオブジェクトが変数に割り当てられると、参照を更新したり、内部状態を変更したりすることはできません。

不変オブジェクトについて詳しく説明した別の記事があります。

詳しくは、https://www.baeldung.com/java-immutable-object[Javaでの可変オブジェクト]の記事を参照してください。

===

3なぜJavaでは

String

不変なのですか?

このクラスを不変にすることの主な利点は、キャッシュ、セキュリティ、同期、およびパフォーマンスです。

これらがどのように機能するのかを説明しましょう。

====

3.1.

String

Pool

を紹介する


String

は最も広く使われているデータ構造です。

String

リテラルをキャッシュして再利用すると、

String

プール内の同じオブジェクトを参照する

String

変数が異なるため、ヒープスペースを大幅に節約できます。

String

インターンプールはまさにこの目的を果たします。

Java String Poolは、

StringがJVMによって格納される

特別なメモリ領域です。

Strings

はJavaでは不変であるため、JVMはプール内の各リテラル

String

のコピーを1つだけ格納することによって、それらに割り当てられたメモリ量を最適化します。このプロセスはインターニングと呼ばれます。

String s1 = "Hello World";
String s2 = "Hello World";

assertThat(s1 == s2).isTrue();

前の例では

String

プールがあるため、2つの異なる変数がプールからの同じ

String

オブジェクトを指しているため、重要なメモリリソースを節約できます。

私たちはJava専用の別の記事を持っています。詳細については、https://www.baeldung.com/java-string-pool[その記事に進んでください]。

====

3.2. セキュリティ


String

は、ユーザー名、パスワード、接続URL、ネットワーク接続などの機密情報を格納するためにJavaアプリケーションで広く使用されています。クラスをロードするときにJVMクラスローダーによっても広く使用されています。

したがって、

String

クラスをセキュリティで保護することは、アプリケーション全体のセキュリティ全般にとって非常に重要です。たとえば、次の簡単なコードスニペットを考えてください。

void criticalMethod(String userName) {
   //perform security checks
    if (!isAlphaNumeric(userName)) {
        throw new SecurityException();
    }

   //do some secondary tasks
    initializeDatabase();

   //critical task
    connection.executeUpdate("UPDATE Customers SET Status = 'Active' " +
      " WHERE UserName = '" + userName + "'");
}

上記のコードスニペットで、信頼できないソースから

String

オブジェクトを受け取ったとしましょう。

String

が英数字のみであるかどうかを確認するために、まず必要なセキュリティチェックをすべて行ってから、さらにいくつかの操作を行います。

信頼できないソース呼び出し元のメソッドは、まだこの

userName

オブジェクトを参照していることを忘れないでください。


  • Strings

    が変更可能な場合、更新を実行するときまでに、セキュリティチェックを実行した後でも、受け取った

    String

    が安全であることを確信できません。整合性チェック間の

    String

したがって、この場合、クエリはSQLインジェクションを起こしやすくなります。そのため、可変の

Strings

は、時間の経過とともにセキュリティが低下する可能性があります。


String


userName

が別のスレッドから見えている可能性もあります。その場合、整合性チェックの後にそのスレッドの値が変わる可能性があります。

結果に影響を与える可能性のある操作のインターリーブが少ないため、値が変更されない場合は機密コードで操作する方が簡単であるため、この場合、不変性が問題になります。

====

3.3. 同期

不変であることは自動的に

String

スレッドを安全にします。なぜならそれらはマルチスレッドからアクセスされたときに変更されないからです。

したがって、** 不変オブジェクトは一般に、同時に実行されている複数のスレッド間で共有できます。スレッドによって値が変更された場合、値を変更するのではなく、新しい

String



String

プールに作成されるためです。したがって、

Strings

はマルチスレッディングに対して安全です。

====

3.4. ハッシュコードキャッシング


String

オブジェクトはデータ構造として豊富に使用されているので、

HashMap



HashTable



HashSet

などのようなハッシュ実装でも広く使用されています。

不変性は、その値が変わらないことを

文字列

に保証します。そのため、ハッシュが最初の

hashCode()呼び出しの間に計算されてキャッシュされ、それ以降同じ値が返されるように、

hashCode()メソッドはキャッシュを容易にするために

String

クラスでオーバーライドされます。

これにより、

String

オブジェクトを操作したときにハッシュ実装を使用するコレクションのパフォーマンスが向上します。

一方、操作後に

String

の内容が変更された場合、可変の

Strings

は挿入および検索時に2つの異なるハッシュコードを生成し、

Map

の値オブジェクトを失う可能性があります。

====

3.5. パフォーマンス

前に見たように、

String

プールは存在します。なぜなら

Strings

は不変だからです。その結果、

Strings.

で操作したときにヒープメモリを節約し、ハッシュ実装へのアクセスを高速化することでパフォーマンスが向上します。


String

は最も広く使用されているデータ構造なので、

String

のパフォーマンスを向上させることは、一般にアプリケーション全体のパフォーマンスを向上させることに大きな効果をもたらします。

===

4結論

この記事を通して、

文字列は正確に不変なので、参照が通常の変数として扱われ、それが指す実際の

String

オブジェクトが変わるかどうかを心配せずに、メソッド間およびスレッド間で渡すことができます。 。

また、

Java

言語設計者がこのクラスを不変にすることを余儀なくされたその他の理由として、これも学んだこともあります。