Как инкапсулировать массив в Java

Я запускаю с Java, и я узнаю о методах set, методах считывания и инкапсуляции. У меня есть очень простая программа, два класса:

  • Container имеет частный международный массив (numArray) с его методом set и методом считывания.

  • Main создает a 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;
    }
}

Проблема: Я могу изменить частный международный массив через метод считывания, я знаю поэтому getNumArray возвращает ссылку на numArray, не сам массив. Если бы я интересовался единственным элементом массива, то я сделал бы метод считывания с индексным значением, но я хочу целый массив для totalArray метод.

Как я могу предотвратить numArray от того, чтобы быть измененным из его класса?

9
задан TT. 14 October 2017 в 06:27
поделиться

4 ответа

Все, что вы можете сделать, чтобы предотвратить изменение массива, это предоставить его копию в геттере.

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

Таким образом, другие методы могут изменить свою собственную копию массива, но когда они снова вызывают геттер, они получают оригинальную версию, без изменений. Только setNumArray(), который вы предоставляете, может на самом деле изменить ваш внутренний массив.

Иначе, если вы хотите полностью заблокировать контейнер, вы должны бросить массивы и использовать неизменяемый объект. Некоторые библиотеки предоставляют неизменяемые списки или используют Collections.unmodifiableList.

.
9
ответ дан 4 December 2019 в 11:42
поделиться

Обычно вы смотрите на интерфейс, который вы пытаетесь предоставить вызывающим абонентам вашего класса.

Методы типа:

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

- это те вещи, которые вы бы предоставили в вашем контейнерном классе. Затем они взаимодействуют с приватным массивом от имени вызывающего абонента.

Если вы хотите вернуть весь массив, не допуская изменений, вы можете в геттере скопировать массив в новый и вернуть копию.

В качестве альтернативы, если вы используете классы коллекции Java вместо примитивного массива, они предоставляют метод unmodifiableXXX() (например, Collections.unmodifiableList(myList)), который предоставляет обертку вокруг коллекции только для чтения.

.
3
ответ дан 4 December 2019 в 11:42
поделиться

Если вы хотите вернуть массив, вы должны клонировать его:

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

В публичном API вы должны быть уверены, что вы четко документируете это вызывающим абонентам (на самом деле, в любом случае, если они получают массив, который изменит состояние класса или нет - они должны знать)

.
6
ответ дан 4 December 2019 в 11:42
поделиться

Инкапсулирование - это процесс сокрытия реализации. Независимо от того, хранится коллекция данных в массиве или нет, это деталь реализации; если она инкапсулирована, вы захотите иметь возможность изменить ее на другой тип хранения.

Сам факт, что вы подвергаете состояние (или производное состояние) как геттеры и сеттеры, нарушает инкапсуляцию и подразумевает, что вы реализуете абстрактный тип данных, а не истинный объектно-ориентированный класс. Например, ArrayList - это тип данных, который не представляет собой никакой истинной инкапсуляции поведения в приложении. Будет ли это то, что вы хотите, зависит от того, как и где этот тип будет использоваться.

Я бы попытался либо заставить Container реализовать Iterable для внешнего взаимодействия, если это просто контейнерный тип данных, либо предоставить внутренний итерационный метод, которому вы передаете посетителя, если он предназначен в качестве инкапсулируемого класса. Если это абстрактный тип данных, то настоятельно рекомендуется использовать вместо него встроенные, такие как int[] или List.

.
0
ответ дан 4 December 2019 в 11:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: