167

このクラスがあると想像してください:

public class Test
{
  private String[] arr = new String[]{"1","2"};    

  public String[] getArr() 
  {
    return arr;
  }
}

さて、上記のクラスを使用する別のクラスがあります。

Test test = new Test();
test.getArr()[0] ="some value!"; //!!!

これが問題です: 外部からクラスのプライベート フィールドにアクセスしてしまいました! どうすればこれを防ぐことができますか? この配列を不変にする方法を教えてください。これは、すべての getter メソッドを使用して、プライベート フィールドにアクセスできるということですか? (Guavaなどのライブラリは必要ありません。これを行う正しい方法を知る必要があるだけです)。

4

11 に答える 11

381

配列の代わりにリストを使用できる場合、コレクションは変更不可能なリストを提供します

public List<String> getList() {
    return Collections.unmodifiableList(list);
}
于 2013-02-11T09:38:38.493 に答える
165

配列のコピーを返す必要があります。

public String[] getArr() {
  return arr == null ? null : Arrays.copyOf(arr, arr.length);
}
于 2013-02-11T09:34:10.633 に答える
45

修飾子privateは、フィールド自体のみを他のクラスからのアクセスから保護しますが、このフィールドによるオブジェクト参照は保護しません。参照されたオブジェクトを保護する必要がある場合は、それを渡さないでください。変化する

public String [] getArr ()
{
    return arr;
}

に:

public String [] getArr ()
{
    return arr.clone ();
}

または

public int getArrLength ()
{
    return arr.length;
}

public String getArrElementAt (int index)
{
    return arr [index];
}
于 2013-02-11T09:34:34.987 に答える
28

Collections.unmodifiableListすでに言及されていますが、Arrays.asList()奇妙なことにそうではありません。私の解決策は、外部からリストを使用して、次のように配列をラップすることです。

String[] arr = new String[]{"1", "2"}; 
public List<String> getList() {
    return Collections.unmodifiableList(Arrays.asList(arr));
}

配列をコピーする際の問題は、コードにアクセスするたびに配列をコピーしていて、配列が大きい場合、ガベージ コレクターに多くの作業が必要になることです。したがって、コピーは単純ですが、非常に悪いアプローチです。「安い」と言えますが、メモリが高価です。特に、要素が 2 つ以上ある場合。

のソースコードを見てみると、Arrays.asList実際Collections.unmodifiableListにはあまり作成されていません。1 つ目は配列をコピーせずにラップするだけで、2 つ目はリストをラップするだけで変更できなくなります。

于 2013-02-11T21:49:34.220 に答える
6

ImmutableList標準よりも優れたものを使用することもできますunmodifiableList。このクラスは、Google によって作成されたGuavaライブラリの一部です。

説明は次のとおりです。

Collections.unmodifiableList(java.util.List) は変更可能な別のコレクションのビューであり、ImmutableList のインスタンスには独自のプライベート データが含まれており、変更されることはありません。

これを使用する方法の簡単な例を次に示します。

public class Test
{
  private String[] arr = new String[]{"1","2"};    

  public ImmutableList<String> getArr() 
  {
    return ImmutableList.copyOf(arr);
  }
}
于 2013-02-12T08:16:49.800 に答える
3

この観点から、システム配列のコピーを使用する必要があります。

public String[] getArr() {
   if (arr != null) {
      String[] arrcpy = new String[arr.length];
      System.arraycopy(arr, 0, arrcpy, 0, arr.length);
      return arrcpy;
   } else
      return null;
   }
}
于 2013-02-12T05:00:14.420 に答える
2

データのコピーを返すことができます。データの変更を選択した発信者は、コピーのみを変更します。

public class Test {
    private static String[] arr = new String[] { "1", "2" };

    public String[] getArr() {

        String[] b = new String[arr.length];

        System.arraycopy(arr, 0, b, 0, arr.length);

        return b;
    }
}
于 2013-02-11T09:41:08.860 に答える
2

問題の核心は、可変オブジェクトへのポインターを返すことです。おっとっと。オブジェクトを不変にする (変更不可能なリスト ソリューション) か、オブジェクトのコピーを返します。

一般的な問題として、オブジェクトが変更可能である場合、オブジェクトのファイナリティはオブジェクトの変更を保護しません。この2つの問題は「いとこ同士のキス」です。

于 2013-02-12T01:43:24.927 に答える
0

はい、配列のコピーを返す必要があります。

 public String[] getArr()
 {
    return Arrays.copyOf(arr);
 }
于 2013-02-11T09:34:50.350 に答える