2013-11-21 85 views
0

我想提出這個聲音處理程序,但我不斷收到此錯誤:爲什麼我的Java深層複製代碼告訴我「作業需要深度而非淺層的副本」?

Assignment requires a deep, not shallow copy. Are you just copying pointers, or copying the contents of the array?...

我想我對我的公共無效集(double[] mySamples)做一個淺拷貝,但我是新來的Java和真的不知道該怎麼做。

public class Sound 
{ 
    private double[] temp; 
    private double[] samples; 

    public Sound() { 
     samples = null; 
    } 

    public Sound(Sound s) { 
     int j = 0; 
     double[] source = s.samples; 
     double temp[] = new double[source.length]; 
     for(int i = 0; i < source.length; i++) { 
      temp[j] = source[i]; 
     } 
     samples = temp; 
    } 

    public double[] get() { 
     return samples; 
    } 

    public void set(double[] mySamples) { 
     if (mySamples == null) { 
      throw new IllegalArgumentException("samples cannot be null"); 
     } else { 
      samples = mySamples; 
     } 
    } 


    public void increaseVol(double percent) { 
     double [] result = new double[samples.length]; 
     for (int i = 0; i < samples.length; i++) { 
      double reduce = samples[i] * percent; 
      result[i] = samples[i] + reduce; 
     } 
     samples = result; 
    } 

    public void wavSave(java.lang.String fileName) { 
     WavIO.write(fileName, samples); 
    } 
} 
+4

請編輯您的代碼,以便顯示合理的縮進。請指出哪一行顯示錯誤。 –

+0

這是我第一次在這個網站上,真的不知道你明智的縮進是什麼意思。無論如何,感謝您的幫助。 – user3079090

+1

您可以將空格添加到應縮進的代碼行中,如代碼塊中的代碼。這與本網站無關,全部是關於基本的Java代碼格式。這很重要,因爲閱讀代碼越容易,幫助你就越容易。現在再次,哪一行顯示你的錯誤? –

回答

1

我認爲你需要做兩個變化 -
你的構造做一些奇怪的那些樣品(並且可能本身會導致你的錯誤) - 我不知道你試圖什麼要做,但我認爲你應該推遲設置。

public Sound(Sound s) { 
    int j = 0; 
    set(s.samples); 
} 

樣品陣列只需複製在集合,並存儲它。

public void set(double[] mySamples) { 
    if (mySamples == null) { 
    throw new IllegalArgumentException(
     "samples cannot be null"); 
    } else { 
    samples = new double[mySamples.length]; 
    for (int i = 0; i < mySamples.length; i++) { 
     samples[i] = mySamples[i]; 
    } 
    } 
} 
+0

非常感謝!它確實解決了我的問題...... – user3079090

0

是的,你正在做「淺」副本。 Java中的數組就像指針一樣,如果你返回或設置一個數組,它只是一個指向該數組的指針(真正的引用)。用你當前的代碼很容易讓不同的Sound對象引用相同的底層數組,這可能不是你想要的。

set方法中,您需要複製數組的內容,而不是將引用複製到該數組。

您可以在Sound(Sound s)的構造函數中正確地複製數組的內容。但是,您不需要手動分配新數組並寫入for-loop來複制值。只需撥打java.util.Arrays.copyOf()即可複製。您可以在set方法中使用類似的技術。

get方法也有問題,它從Sound對象中返回對數組的引用。調用者現在可以引用Sound對象的內部狀態,並可以對其進行操作。這可能或可能不是你想要的。

0

原始數組和自動註冊引用類型(來自基元)的數組是最終的且不可變的。因此,它們是clone()方法的理想候選。

您可以編輯該代碼:

public void set(double[] mySamples) { 
    if (mySamples == null) { 
     throw new IllegalArgumentException(
      "samples cannot be null"); 
    } else { 
     samples = new double[mySamples.length]; 
     for (int i = 0; i < mySamples.length; i++) { 
      samples[i] = mySamples[i]; 
     } 
    } 
} 

到這個具有相同的功能和卓越的性能:

public void set(double[] mySamples) { 
    if (mySamples == null || mySamples.length < 1) { 
     throw new IllegalArgumentException(
      "samples cannot be null or empty"); 
    } 
    samples = mySamples.clone(); 
} 

這工作安全,因爲double s爲不可變的,原始的,所以淺副本在這種情況下與深拷貝相同。這也是安全的,因爲double不能被分類,所以clone()也沒有惡作劇的可能。

此外,數組上的clone()的性能比遍歷代碼中的數組和逐個元素複製要快得多。

TL; DR:製作原始數組副本(或相應自動裝箱參考類型的數組對應於原語)很可能是使用clone()方法的唯一理想情況。