なぜJavaの中のString類は可変ではないですか?


JavaではStringタイプが可変対象ではないことは間違いないですが、Java言語の設計者はなぜStringタイプを可変対象外に設計するのですか?これは考えるべき問題だ。
Java言語の創設者であるJames Goslingは、一度のインタビューで、可変ではないオブジェクトをいつ使うべきかと聞かれました。
その前に、まず簡単に調べてみます。何が可変の対象ですか?
可変オブジェクトとは、オブジェクトが作成された後、オブジェクトの内部状態およびオブジェクトのメモリポインタアドレスが変更されないことを意味します。Javaの中でfinalのキーワードは可変オブジェクトの作成を支援するために使われていますが、基本的なタイプがfinalによって修飾された後、完全に可変オブジェクトではなく、引用タイプがfinalによって修正された後、ポインタだけのメモリアドレスは変更できません。オブジェクト内のすべてのフィールドをFinalで宣言するには、入れ子のオブジェクトを含めて、オブジェクトの内部の状態が変化します。この点は理解してください。
ok、なぜStringは可変ではないかを分析します。
Stringソースによって、Stringタイプの最下層はfinalによって修正されたchar配列によって保存されていることが分かります。

public final class String
  implements java.io.Serializable, Comparable<String>, CharSequence {
  /** The value is used for character storage. */
  private final char value[];
  
  ........
  }
Stringは可変ではないタイプに設計できる重要な前はプログラミング言語の中で使用頻度が一番高いタイプだからです。可変タイプによってもたらされるメリットは、キャッシュ、セキュリティ、同期、およびパフォーマンスの4つの側面に現れています。
(一)キャッシュ
JVMの運転時のデータエリアには、次のコードのような文字列の文字列の文字列量を格納するための専用の文字列定数があります。

String s1 = "Hello World";
String s2 = "Hello World";
     
assertThat(s1 == s2).isTrue();
s 1とs 2変数ポインタのメモリアドレスは同じです。つまり彼らの代表は同じ対象です。これはjvm定数プールの最適化です。最初の文字列量声明の時、その値は文字列常量池に保存されます。s 2変数宣言の時、jvmは常量池にその対象がすでに存在していることを発見しました。だからもう一回作成しません。同じメモリポインタを直接s 2変数に割り当てることで、重複してオブジェクトを作成することを避け、メモリ空間を節約します。
また、文字列の可変性がないので、hashCodeもキャッシュされ、Javaではハッシュクラスのデータ構造がhashMap、hashTable、hashSetではkey用のほとんどがStringタイプとなり、keyのhashCodeも最初の呼び出し後にキャッシュされ、そのまま使用して再生成する必要がなく、間接的にアクセス効率を向上させることができる。
(二)安全
可変性のない特性は、次のコードのように、アプリケーションの動作時間におけるセキュリティ問題を低減することもできる。

void criticalMethod(String userName) {
  // check
  if (!check(userName)) {
    throw new SecurityException(); 
  }
   
  // query 
  query(userName);
  
  }
上記のコードの中で、この方法を呼び出した後、ユーザー名を確認し、合法的であれば関連データを継続して調べることができます。もしStringが可変であれば、攻撃者はcheckで検証してから、クエリのユーザ名を変更することができます。一方、Stringが可変であれば、同時に実行される他のスレッドがこの値を修正すれば、混乱を招く可能性がある。
(三)同期
Stringタイプの不変性のために、Stringオブジェクトは複数のスレッド間で安全に転送・アクセスできるようになりました。つまり、マルチスレッドで文字列自体の値を変更することはできません。スタックの中で新しい文字列を作成してから動作します。もちろんfinal修飾がない場合は、この変数の参照アドレスを変更することができます。つまり、新たに生成されたメモリを元の変数参照に上書きすることができます。ここでは参照だけで、変数の値ではありません。この点に注意します。
(四)性能
性能については、前述したように、文字列の常量池でメモリを節約し、キャッシュHash類は文字列でkeyデータ構造のhashCodeを作り、アクセス性能を向上させるなどしています。文字列はプログラミング言語の中で最も広く使われているデータ構造なので、文字列の非変性に対する利点は、実行全体のアプリケーションに増幅され、アプリケーション全体の性能向上をもたらします。
まとめ:
本論文は主にJava言語の中のStringタイプがなぜ可変タイプに設計されたのかを紹介し、可変タイプの持つ主要な利点を分析した。可変タイプではないが、多くの利点をもたらすことができるが、その欠点がないというわけではなく、可変タイプの修正ごとにメモリの中で一つの対象として生まれ変わる必要がある。もう一つの面では、常に変化する対象に対して不可変タイプを使うのは不適切であり、これもなぜJavaに修正可能な値を提供しているStringBuiderとStringBuffer類であり、これは実際の開発においては常に状況に応じたバランスが必要である。
以上述べたのは小编です。なぜJavaの中のString类は可変的ではないかということを绍介しました。皆さんに何かお聞きしたいことがあれば、メッセージをください。小编はすぐにご返事します。ここでも私たちのサイトを応援してくれてありがとうございます。