web-dev-qa-db-ja.com

ソナー違反:セキュリティ-配列は直接保存されます

ソナー違反があります:

ソナー違反:セキュリティ-配列は直接保存されます

public void setMyArray(String[] myArray) { 
  this.myArray = myArray; 
} 

解決策:

public void setMyArray(String[] newMyArray) { 
  if(newMyArray == null) { 
    this.myArray = new String[0]; 
  } else { 
   this.myArray = Arrays.copyOf(newMyArray, newMyArray.length); 
  } 
}

しかし、なぜだろうか?

60
Junchen Liu

格納している配列が、呼び出し元が保持しているのと同じ配列であると不平を言っています。つまり、呼び出し元がその後この配列を変更すると、オブジェクト(およびオブジェクト自体)に格納されている配列が変更されます。

解決策は、オブジェクトが渡されたときにオブジェクト内にコピーを作成することです。これはdefensive copyと呼ばれます。コレクションのその後の変更は、オブジェクト内に格納されている配列には影響しません。

コレクションを返すときに通常はこれを行うこともお勧めです(たとえば、対応するgetMyArray()呼び出しで)。そうしないと、受信者が変更を実行し、保存されたインスタンスに影響を与える可能性があります。

これは、配列だけでなく、すべての可変コレクション(および実際にはすべての可変オブジェクト)に明らかに適用されることに注意してください。また、これにはパフォーマンスへの影響があり、他の懸念事項とともに評価する必要があることに注意してください。

51
Brian Agnew

これは防御コピーと呼ばれます。このトピックに関する素晴らしい記事は "Whose object is it、とにかく?" Brian Goetzによるもので、ゲッターとセッターの値と参照セマンティクスの違いについて説明しています。

基本的に、参照セマンティクス(コピーなし)のリスクは、誤って配列を所有していると考え、その配列を変更すると、配列のエイリアスを持つ他の構造も変更することです。防御的なコピーやオブジェクトのエイリアシングに関連する問題に関する多くの情報をオンラインで見つけることができます。

21
ewernli

私は同じ問題を抱えていました:

セキュリティ-配列はユーザ​​ーが指定した配列に直接格納されます'palomitas'は直接格納されます。

私の元の方法:

public void setCheck(boolean[] palomitas) {
        this.check=palomitas;
    }

修正済み:

public void setCheck(boolean[] palomitas) { 
      if(palomitas == null) { 
        this.check = new boolean[0]; 
      } else { 
       this.check = Arrays.copyOf(palomitas, palomitas.length); 
      } 
}

その他の例:

セキュリティ-配列はユーザ​​ーが指定した配列に直接格納されます

private String[] arrString;

    public ListaJorgeAdapter(String[] stringArg) {      
        arrString = stringArg;
    }

一定:

public ListaJorgeAdapter(String[] stringArg) {  
    if(stringArg == null) { 
      this.arrString = new String[0]; 
    } else { 
      this.arrString = Arrays.copyOf(stringArg, stringArg.length); 
    } 
}
12
Jorgesys

これらを排除するには、次のクラス実装に示すように、配列を保存または返す前に配列を複製する必要があります。したがって、クラスの元のデータを変更または取得することはできません。

public byte[] getarrString() {
    return arrString.clone();
}
/**
 * @param arrStringthe arrString to set
 */
public void arrString(byte[] arrString) {
    this.arrString= arrString.clone();
}

私はこのように使用しましたが、SONAR違反はありません...

3
Wolverine789

これよりも簡単です。 Sonar違反を避けるために、メソッドパラメータの名前を他のものに変更するだけです。

http://osdir.com/ml/Java-sonar-general/2012-01/msg00223.html

public void setInventoryClassId(String[] newInventoryClassId)
    {                
            if(newInventoryClassId == null)
            {
                    this.inventoryClassId = new String[0];
            }
            else
            {
                    this.inventoryClassId = Arrays.copyOf(newInventoryClassId, newInventoryClassId.length);
            }

    } 
2
Sky Games Inc

設計上の決定であり、見逃さない特定のケースがあります。このような場合、Sonarルールを変更して除外し、レポートにそのような問題が表示されないようにする必要があります。

0
Tushar Patel

防御的な実装方法を使用すると、時間を大幅に節約できます。グアバでは、目標を達成するためのもう1つの素晴らしいソリューション、ImmutableCollectionsを取得します。

http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained

0
Jordi Laforge