2012-07-20 38 views
59

有一個聲納違規:聲納違規:安全 - 陣列直接存儲

聲納違規:安全 - 陣列直接存儲

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

但我想知道爲什麼?

+10

嗯...這個解決方案沒有工作對我來說,其實。聲納仍然拿起它並抱怨,儘管做了一個副本。 – ndtreviv 2013-10-07 15:30:51

+1

@ndtreviv所以你如何解決它? – sakura 2014-03-27 13:32:46

+2

@ndtreviv:我也遇到過這個問題,如果提供給方法的本地變量的名稱與您正在存儲的實例變量相同,則此錯誤不會消失。確保它們不同,並且上述解決方案應該可以工作。 我通過以下鏈接找到了這個[鏈接](http://sonarqube.15.x6.nabble.com/Security-Array-is-stored-directly-weirness-td3632714.html) – Matt 2014-06-03 21:00:56

回答

52

這是抱怨你正在存儲的數組是由調用者持有的相同數組。也就是說,如果調用者隨後修改這個數組,那麼存儲在該對象中的數組(也就是對象本身)將會改變。

解決方案是在對象通過時創建副本。這叫做防禦性複製。集合的後續修改不會影響存儲在對象中的數組。

通常在返回集合時(例如,在相應的getMyArray()調用中)這樣做也是很好的做法。否則,接收方可以執行修改並影響存儲的實例。

請注意,這顯然適用於所有可變集合(實際上所有可變對象) - 不只是數組。還要注意,這具有性能影響,需要與其他問題一起評估。

+0

我可以看到原因....如果我故意要調用者和其目標持有相同的副本? – 2012-07-20 15:23:07

+2

這是一個設計決定。但我認爲了解誰擁有這些數據非常重要,以及如何(如有必要)通知持有該數據的對象已更改。在沒有防禦性複製的情況下,與通過收藏密切相關的一組組件是非常合理的。但是在某些時候會有一個你需要保護自己的邊界(例如插入第三方或客戶的代碼) – 2012-07-20 15:30:13

+1

當然OP *是*用this.myArray = Arrays.copyOf( newMyArray,newMyArray.length);'? – Qwerky 2012-10-04 14:25:50

22

它被稱爲防禦性複製。關於這個主題的一篇很好的文章是Brian Goetz的"Whose object is it, anyway?",它討論了getter和setter的值和引用語義之間的區別。

基本上,引用語義(沒有副本)的風險是您錯誤地認爲自己擁有數組,並且在修改它時,還要修改其他具有數組別名的結構。您可以在線找到許多有關防止複製和與對象別名有關的問題的信息。

+0

感謝隊友,def a up投票。你能舉一個小例子,還是用50個字來壓縮原因? – 2012-07-20 14:08:08

+1

@ewernli:鏈接被破壞,請修復它。謝謝! – 2013-11-18 05:36:47

+1

@KugathasanAbimaran鏈接再次運作! – ewernli 2014-01-28 16:02:55

12

我有同樣的問題:

安全 - 陣列直接存儲用戶提供的陣列 '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); 
    } 
} 
2

消除它們,你必須克隆存儲/恢復它在下面的類實現顯示前陣,因此沒有人可以修改或獲得的原始數據你的班級,但只有他們的副本。

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

我用它這樣的,現在我沒有得到任何違反SONAR ...

0

有某些情況下,這是一個設計決策,而不是錯過了。在這些情況下,您需要修改Sonar規則以排除它,以便它不會在報告中顯示此類問題。

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

    }