65

存在声纳违规:

声纳违规:安全 - 阵列直接存储

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); 
  } 
}

但我想知道为什么?

4

7 回答 7

54

它抱怨您存储的数组与调用者持有的数组相同。也就是说,如果调用者随后修改了这个数组,那么存储在对象中的数组(以及对象本身)将会改变。

解决方案是在对象被传递时在对象内制作副本。这称为防御性复制。对集合的后续修改不会影响存储在对象中的数组。

在返回集合时(例如在相应的getMyArray()调用中)通常这样做也是一种很好的做法。否则接收器可能会执行修改并影响存储的实例。

请注意,这显然适用于所有可变集合(实际上是所有可变对象)——而不仅仅是数组。另请注意,这会对性能产生影响,需要与其他问题一起评估。

于 2012-07-20T14:08:55.723 回答
22

这被称为防御性复制。关于该主题的一篇不错的文章是“无论如何,它是谁的对象?” Brian Goetz 讨论了 getter 和 setter 的值和引用语义之间的区别。

基本上,引用语义(没有副本)的风险是您错误地认为您拥有该数组,并且当您修改它时,您还修改了具有该数组别名的其他结构。您可以在线找到许多关于防御性复制和与对象别名相关的问题的信息。

于 2012-07-20T14:04:41.657 回答
13

我遇到过同样的问题:

安全性 - 数组直接存储用户提供的数组 “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); 
    } 
}
于 2014-01-17T18:45:09.060 回答
4

要消除它们,您必须在存储/返回它之前克隆数组,如以下类实现所示,因此没有人可以修改或获取您的类的原始数据,而只能是它们的副本。

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

我像这样使用它,现在我没有收到任何违反声纳的行为......

于 2014-07-16T09:50:45.440 回答
2

这比这一切都容易。您只需要将方法参数重命名为其他任何名称,以避免违反声纳。

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);
            }

    } 
于 2016-01-12T09:48:59.893 回答
0

采取防御性实施方式可以为您节省大量时间。在 Guava 中,您可以获得另一个很好的解决方案来实现目标:ImmutableCollections

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

于 2012-11-28T11:46:05.747 回答
0

在某些情况下,这是一个设计决策,不会错过。在这些情况下,您需要修改 Sonar 规则以将其排除,以便它不会在报告中显示此类问题。

于 2015-10-14T11:15:54.370 回答