他にも、プリミティブ型でない限り、オブジェクトへの参照があります。これはC++のポインタと似ていますが、オブジェクトにアクセスすることはできますが、C++リファレンス(変数のメモリアドレスへのポインタ)とは異なり、別のオブジェクトと置き換えることはできません。セッターだけがそれを行うことができます。
質問には2種類あります。test.getArray().remove(0)
とaVar.remove(0)
です。それらの結果には違いはありませんが、それはまだポインタのような参照であり、元のものを変更します。
getterを呼び出すだけでクローンを取得することはないので、オブジェクトが不変でない限り、ゲッターがアクセス権を与えたオブジェクトを変更できます。たとえば、String
は不変ですが、任意の基本Collection
(ArrayList
を含む)は変更可能です。 Collections.unmodifiable*(...)
に電話してコレクションを変更できないようにすることができます。ただし、コレクションの項目が変更可能な場合でも変更することができます。
場合によっては、クローンを取得することは良い考えです。ほとんどの場合、そうではありません。 getterは何も複製してはいけません。nullの可能性のあるコレクションなどを初期化しない限り、データを変更すべきではありません。不変オブジェクトを含む変更不可能なコレクションが必要な場合は、このようにしてください。この例では、後で説明する理由Foo
を実装するクラスFooImpl
があります。
public interface Foo {
int getBar();
}
public class FooImpl Foo {
private int bar;
@Override
public int getBar() {
return bar;
}
public void setBar(int newValue) {
this.bar = newValue;
}
}
ご覧のとおり、Fooにはセッターがありません。 ArrayList<Foo>
を作成してゲッターからCollections.unmodifiableList(myArrayList)
として渡すと、ほとんどあなたがやったようです。しかし、仕事はまだ行われていません。クラスFooImpl
が公開されている場合(この場合)、リスト内に見つかったfoo
がinstanceof FooImpl
である場合、誰かが試してみる可能性があります。それを(FooImpl) foo
として変更可能にしてください。ただし、Foo
はFooWrapper
というラッパーにラップできます。それだけでなくFoo
を実装します。
public class FooWrapper implements Foo {
private Foo foo;
public FooWrapper(Foo foo) {
this.foo = foo;
}
public int getBar() {
return foo.getBar();
}
// No setter included.
}
その後、我々はCollection<FooWrapper>
にnew FooWrapper(myFoo)
を置くことができます。このラッパーにはパブリックセッターはなく、内部のfooはプライベートです。基礎となるデータは変更できません。今度はFoo
インターフェイスについて。 FooImpl
とFooWrapper
の両方が実装されていますが、いずれの方法でもデータを変更しようとしない場合、入力時にFoo
を入力することができます。どのFoo
を取得するかは関係ありません。
したがって、変更不可能なデータを含む変更不可能なコレクションを作成する場合は、オブジェクトをフィードし、Collections.unmodifiable*(theCollection)
を呼び出して新しいCollection<Foo>
を作成します。または、例えば、FooWrappersを返し、このリストはFooのコレクション全体をラップカスタムコレクションます包まれたコレクションで
public MyUnmodifiableArrayList implements List<Foo> {
ArrayList<Foo> innerList;
public get(int index) {
Foo result = innerList.get(index);
if (!(result instanceof FooWrapper)) {
return new FooWrapper(result);
}
return result; // already wrapped
}
// ... some more List interface's methods to be implemented
}
を、あなたは、元のコレクションを反復処理とのラッパーとそのクローンを作成する必要はありませんデータ。この解決策は、全体を読むのがはるかに優れていますが、そのインデックスのFooがすでにFooWrapper
でない限り、get()
を呼び出すたびに新しいFooWrapperが作成されます。 get()
への何百万回の呼び出しで長時間実行されているスレッドでは、これはガベージコレクタの不要なベンチマークになる可能性があり、既存のFooWrappersを含む内部配列またはマップを使用できます。
新しいカスタムList<Foo>
を返品することができます。しかし、再び、普通のゲッターからではありません。 private ArrayList<FooImpl> fooList
フィールドにはgetUnmodifiableFooList()
のようになります。
Javaはオブジェクトをコピーしません。 – SLaks
この例では、ゲッターはオブジェクトをどこで変更しますか? – raina77ow
確認しやすいようです。実際には、変更が元の配列に影響するように、参照のみがあなたの例で渡されます。 – assylias