2010-01-05 99 views
8

我開始使用Java,我正在學習setter,getters和encapsulation。我有一個非常簡單的程序,兩類:如何在Java中封裝數組

  • Container有私家int數組(numArray)與他的二傳手&吸氣。

  • Main創建一個Container對象並在totalArray方法中使用它。


public class Container { 
    private int numArray[]= {0,0,0}; 
    public int[] getNumArray() { 
     return numArray; 
    } 
    public void setNumArray(int index, int value){ 
     numArray[index] = value; 
    }  
} 

public class Main { 
    public static void main(String[] args) { 
     Container conte = new Container(); 
     System.out.println(totalArray(conte.getNumArray())); 
     conte.getNumArray()[2]++; 
     System.out.println(totalArray(conte.getNumArray())); 
    } 
    private static int totalArray (int v[]){ 
     int total=0; 
     for (int conta =0; conta<v.length;conta++){ 
      total+=v[conta]; 
     } 
     return total; 
    } 
} 

問題:我可以通過吸氣更改專用int數組,我知道那是因爲getNumArray返回一個參考numArray,而不是數組本身。如果我對數組中的單個元素感興趣,我會創建一個具有索引值的getter,但我想要整個數組用於totalArray方法。

如何防止numArray被他的班級修改?

回答

8

所有你可以做的,以防止人們改變你的數組是爲了在getter中提供它的副本。

public int[] getArray() { 
    return Arrays.copyOf(numArray, numArray.length); 
} 

這種方法,其他的方法可以更改自己的數組的拷貝,但是當他們再次撥打,吸氣,他們得到的原始版本,持平。只有您提供的setNumArray()實際上可以修改您的內部陣列。否則,如果要完全阻止容器,則必須刪除數組並使用不可變對象。 Some庫提供不可變列表,或使用Collections.unmodifiableList

+0

'Some'與標準Java庫中的一樣。 – 2010-01-05 15:49:45

+1

@Pete:是的,但不只是。 – glmxndr 2010-01-05 15:58:19

3

通常你會看看你正在嘗試提供給你的類的調用者的接口。

的方法,如:

void addItem(Object item); 
Object getItem(int index); 
int getSize(); 

是那種事情,你會提供您的容器類。然後他們代表調用者與私有數組進行交互。

如果你想在不允許修改的情況下返回整個數組,你可以在getter中將數組複製到新的數組中並返回副本。或者,如果您使用Java集合類而不是基本數組,則它們提供了一個不可修改的XXX()方法(例如Collections.unmodifiableList(myList)),它們爲集合提供只讀封裝。

+1

請修復您的方法名稱。 Java方法以小寫字母開頭,Object是一個類(大寫)。 – 2010-01-05 15:11:53

+0

謝謝,當你花一天時間看C#時,會發生什麼......) – Paolo 2010-01-05 15:32:05

+1

+1:通過**封裝你的數組而不暴露數組的存在**!使容器具有豐富的接口,該接口代表該類上的實際功能,而不是僅僅根據需要將其內部數據成員返回給調用者。 – 2010-01-05 16:12:09

6

如果你想返回一個數組,你會複製它:

public int[] getArray() { 
     return (int[]) numArray.clone(); 
    } 

在一個公共的API,你應該確保文檔,清楚地給市民(實際上任何一種方式,如果他們得到一個數組這會改變課堂的狀態 - 他們需要知道)。

0

封裝是隱藏實現的過程。集合是否將其數據存儲在數組中是一個實現細節;如果封裝了它,則希望能夠將其更改爲另一種存儲類型。

這一事實本身您正在曝光狀態(或衍生的狀態)getter和setter斷裂包封和暗示要實現抽象數據類型而不是真正的面向對象的類。例如,ArrayList是一種數據類型,它不表示應用程序中的任何行爲封裝。這是否是你想要的取決於類型的使用方式和位置。

我會傾向於要麼使Container實施Iterable<Integer>外部互爲作用,如果它是一個簡單的容器數據類型,或提供一個內部迭代方法,其傳遞一個訪問者,如果它打算作爲封裝類。如果是抽象數據類型,請考慮使用內置的數據類型,例如int[]List<Integer>

0

還有另外一種方法,它不構成數組的副本,但有其他缺點。我會用它非常大的陣列:

private A[] items; 

public List<A> getItems() { 
    return Collections.unmodifiableList(Arrays.asList(items)); 
} 
0

我想建議一個不同的方法從我在這裏看到的所有答案。當你考慮封裝的時候,它會很方便,同時考慮一下規則:「不要問一個對象的數據,要求一個對象對你的數據進行操作」。

你沒有給我一個numArray的用法,我打算假裝你的目標是從數學(而不是Java矢量)爲例創建一個數值「Vector」。

因此您創建一個包含雙精度數組的NumericVector類。您的NumericVector將具有像multiplyByScalar(double scalar)和addVector(NumericVector secondVector)添加元素的方法。

你的內部數組是完全封裝的 - 它永遠不會逃脫。任何對其進行的操作都是通過這些「業務方法」在您的NumericVector類中完成的。如何在操作後顯示它?讓NumericVector覆蓋NumericVector.toString()以便正確打印輸出,或者如果您有GUI,請編寫一個「Controller」類以將數據從Model(NumbericVector)傳輸到您的視圖(GUI)。這可能需要從您的NumericVector流式傳輸元素。

這也表明一些事情要避免:不要自動創建setter和getters,它們會破壞封裝。你經常需要getter,但正如其他人所說的那樣,你應該讓你的getter返回一個不可變的數組版本。儘可能使你的類不可變。我之前提到的那種方法numericVector.addVector(NumericVector secondVector)可能不應修改numericVector,但返回一個新的NumericVector與解決方案。

這個(和一般的OO)往往失敗的情況是庫 - 當你想要爲你的數組增加一點功能但仍然將它作爲一個通用數組的時候。在這種情況下,Java通常不會打擾封裝,它只是添加一個輔助方法/類,它可以對集合/數組執行操作(查看「Arrays」對象獲取大量示例)。

0

如何封裝陣列中的Java

的問題可能是很清楚,但我想OOP點是設計一類爲操縱這個陣列和實體提取它自己的api。

如果你堅持下去,然後返回陣列/防守副本克隆是去簡單的情況下的方式。

0

存儲器高效的方法來做到這一點是...

package com.eric.stackoverflow.example; 

import java.util.List; 

import com.google.common.collect.ImmutableList; 

public class Container { 
    private int numArray[] = {0, 0, 0}; 
    public int[] getNumArray() { 
     return ImmutableList.copyOf(numArray); 
    } 
    public void setNumArray(int index, int value) { 
     numArray[index] = value; 
    }  
} 

這允許ImmutableList設置List的背襯數組中的項的正確數量,並減少所創建的中間對象的數目。