16

この Java チュートリアル では、不変オブジェクトは作成後にその状態を変更できないと述べています。

java.lang.Stringフィールドを持つ

/** Cache the hash code for the string */
private int hash; // Default to 0

メソッドの最初の呼び出しで初期化されるhashCode()ため、作成後に変更されます。

    String s = new String(new char[] {' '});
    Field hash = s.getClass().getDeclaredField("hash");
    hash.setAccessible(true);
    System.out.println(hash.get(s));
    s.hashCode();
    System.out.println(hash.get(s));

出力

0
32

String不変と呼ぶのは正しいですか?

4

9 に答える 9

13

より適切な定義は、オブジェクトが変更されないということではなく、変更されたことを観察できないということです。その動作は決して変わることはありません。.substring(x,y)その文字列equalsと他のすべてのメソッドに対して常に同じものを返します。

その変数は、最初の呼び出し時に計算.hashcode()され、以降の呼び出しのためにキャッシュされます。これは基本的に、関数型プログラミング言語で「メモ化」と呼ばれるものです。

リフレクションは実際には「プログラミング」のためのツールではなく、むしろメタプログラミング (つまり、プログラムを生成するためのプログラムのプログラミング) のためのツールであるため、実際にはカウントされません。これは、メモリ デバッガーを使用して定数の値を変更するのと同じです。

于 2013-03-07T15:55:44.593 に答える
8

「不変」という用語は、正確な定義ができないほどあいまいです。

Eric Lippert のブログのKinds of Immutabilityを読むことをお勧めします。技術的には C# の記事ですが、提起された質問にかなり関連しています。特に:

観察的不変性:

メソッドを呼び出したり、フィールドを見たりするたびに同じ結果が得られるというプロパティを持つオブジェクトがあるとします。呼び出し元の観点からは、そのようなオブジェクトは不変です。ただし、オブジェクトが舞台裏で遅延初期化を行ったり、関数呼び出しの結果をハッシュ テーブルに記憶したりしていることは想像に難くありません。オブジェクトの「内臓」は完全に変更可能である可能性があります。

何が問題なのですか?本当に深く不変なオブジェクトは、内部状態をまったく変更しないため、本質的にスレッドセーフです。オブジェクトが「同時に」2 つのスレッドで呼び出された場合に、内部の可変状態を破損から保護するために、バックグラウンドで変更可能なオブジェクトには、複雑なスレッド コードが必要になる場合があります。

于 2013-03-08T05:37:21.020 に答える
3

作成されると、インスタンスのすべてのメソッドString(同じパラメーターで呼び出される) は、常に同じ結果を提供します。その動作を (パブリック メソッドで) 変更することはできないため、常に同じエンティティを表します。またfinal、サブクラス化できないため、すべてのインスタンスがこのように動作することが保証されています。

したがって、パブリックビューから、オブジェクトは不変と見なされます。この場合、内部状態はあまり重要ではありません。

于 2013-03-07T15:53:42.360 に答える
1

はい、それらを不変と呼ぶのは正しいです。

privateクラスの... および... 変数にアクセスして変更できることは事実ですが、オブジェクトfinalに対して行うのは不必要で信じられないほど賢明ではありません。String一般に、誰もそれを行うほど夢中になることはないと想定されています。

セキュリティの観点から、文字列の状態を変更するために必要なリフレクション呼び出しはすべて、セキュリティ チェックを実行します。サンドボックスの実装に誤りがない限り、信頼されていないコードの呼び出しはブロックされます。したがって、信頼されていないコードがサンドボックスのセキュリティを破る可能性があるため、これについて心配する必要があります。

finalまた、リフレクションを使用して変更すると、問題が発生する可能性があり (マルチスレッドなど)、効果がない可能性があると JLS が述べていることも注目に値します。

于 2013-03-07T15:51:50.290 に答える
0

外部から変更することはできず、最終クラスであるため、サブクラス化して変更可能にすることはできません。これらは不変性の2つの要件です。リフレクションはハックと見なされ、通常の開発方法ではありません。

于 2013-03-07T15:45:50.717 に答える
0

リフレクションを使用すると、プライベート フィールドの内容を変更できます。したがって、Javaの不変オブジェクトを呼び出すのは正しいですか?

不変性とは、アプリケーションによって開始された、またはアプリケーションによって認識可能な変更を指します。

文字列の場合、特定の実装がハッシュコードを遅延計算することを選択したという事実は、アプリケーションには認識されません。さらに一歩進んで、オブジェクトによってインクリメントされるが、決して公開されず、他の方法で使用されることのない内部変数も、「不変」オブジェクトで受け入れられると言います。

于 2013-03-07T15:46:10.403 に答える
0

クラスは、可変フィールドへのアクセスを提供しない限り、可変フィールドを持ちながら不変にすることができます。

設計上、不変です。リフレクションを使用する場合 (宣言されたフィールドを取得し、そのアクセシビリティをリセットする)、その設計を回避しています。

于 2013-03-07T15:46:52.523 に答える