В Java не допускайте изменения поля после его возврата методом экземпляра - PullRequest
4 голосов
/ 16 февраля 2009

На уроке по разработке программного обеспечения в моем университете учитель постоянно упоминал, что в викторине нам нужно было убедиться, что поле, возвращаемое получателем, необходимо "защитить". Я предполагаю, что она имела в виду, что ничто вне класса не сможет изменить это. Она не дала гораздо большего объяснения, чем это.

Например:

class Foo {
    string[] bar = <some array contents>;

    public string[] getBar() {
        return bar;
    }
}

Любой код, вызывающий getBar, сможет изменять элементы в этом массиве. Как вы предотвращаете это? Я предполагаю, что сам объект должен иметь возможность изменять массив, но не что-либо вне объекта.

Это не домашняя помощь, так как тесту пару недель. Я просто хочу лучше понимать Java, поскольку мой учитель не очень хорошо объяснял.

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

Ответы [ 6 ]

8 голосов
/ 16 февраля 2009

Вы либо используете коллекцию и переносите ее в Collections.unmodifiable * (), либо защищенно копируете свой массив, коллекцию или объект, если он изменяемый (который всегда есть).

Например:

class Foo {
    private String[] bar = <some array contents>;

    public String[] getBar() {
        return bar == null ? bar : Arrays.copyOf(bar);
    }
}

То, что вы должны остерегаться, это то, что это мелкая копия (как и клон). Не уверен, в чем была проблема твоего учителя с клоном.

5 голосов
/ 16 февраля 2009

Просто добавьте к одному из предыдущих ответов, вы хотите убедиться, что с коллекцией вы не используете метод clone () для достижения того, чего вы пытаетесь достичь здесь. Это создает только поверхностную копию коллекции, все ссылки на объекты, содержащиеся в копии коллекции, все еще указывают на те же объекты, что и в оригинале, например, объекты в копии коллекции все еще могут быть изменены, хотя оригинальная коллекция не может. Убедитесь, что вы делаете глубокую копию возвращенной коллекции, если это то, что вы пытаетесь сделать.

3 голосов
/ 16 февраля 2009

Я подозреваю, что она имела в виду, что видимость самого поля должна быть protected (или private), чтобы доступ осуществлялся только через геттер. В случае коллекции вы также можете сделать то, что предлагает @cletus, и вернуть копию коллекции, если вы не хотите, чтобы она была изменена вне класса. РЕДАКТИРОВАТЬ Исходя из ваших правок, она, вероятно, имела в виду оба.

class Foo {
    protected string[] bar = <some array contents>;

    public string[] getBar() {
        return bar;
    }
}
1 голос
/ 16 февраля 2009

Пожалуйста, сообщите профессору, что все неконечные поля должны быть приватными , чтобы сохранить инкапсуляцию.

Защищено позволяет вашему подклассу или другим классам в том же пакете изменять поле без вашего ведома.

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

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

1 голос
/ 16 февраля 2009

Я бы добавил к первому предложению cletus - самый простой способ сделать неизменным bar - это использовать List вместо массива и вернуть его, завернутый в unmodifiableList. Таким образом, клиенту класса сразу становится понятно, что содержимое бара нельзя изменить - генерируется исключение UnsupportedOperationException. Возиться с глубоким клонированием, вероятно, будет довольно неэффективно, в зависимости от сложности ваших объектов, и все равно возвращает кучу изменяемых объектов - просто любые изменения, внесенные в них, будут игнорироваться Foo.

class Foo {
  private List<String> bar = new ArrayList<String>();
  public Collection<String> getBar() {
    return Collection.unmodifiableList(bar);
  }
}

(Также стоит отметить, что с обобщениями в Java 5+ список ведет себя гораздо больше как массив, чем раньше).

1 голос
/ 16 февраля 2009

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

Если поле является изменяемым объектом, то снова его значение можно изменить. Для этого вам необходимо выполнить глубокое клонирование, прежде чем возвращать этот объект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...