Использовать сеттеры в конструкторах Java [duplicate]

Чтобы использовать методы и член объекта, вам сначала нужно создать этот объект. Если вы его не создали (переменная, которая должна содержать объект, не инициализируется), но вы пытаетесь использовать его методы или переменные, вы получите эту ошибку.

Иногда вы можете просто забыть инициализировать .

Отредактировано: new не может вернуть значение null, но исключение огня при ошибке. Давно это было на некоторых языках, но не больше. Спасибо @John Saunders за указание на это.

55
задан Billworth Vandory 4 February 2011 в 02:08
поделиться

9 ответов

Лично я бы установил переменную непосредственно в случаях most .

Методы обычно ожидают, что экземпляр полностью сформирован к тому времени, когда они называется. В частности, вызов переопределенного метода из конструктора является рецептом для трудно понятного кода и труднодоступных ошибок.

Сказав это, я часто стараюсь сделать классы неизменными в любом случае, в которых в случае не существует сеттера, но у вас есть , чтобы в конечном итоге установить конечную переменную из конструктора (или инициализатора переменной):)

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

72
ответ дан Jon Skeet 3 September 2018 в 17:17
поделиться

Я следую двум правилам о конструкторах, чтобы свести к минимуму проблемы, поэтому я не буду использовать метод мутатора:

Конструкторы (не конечных классов) должны вызывать только конечные или частные методы . Если вы решите игнорировать это правило и позвольте конструктору вызывать нефинальные / не частные методы, то:

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

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

[[@Jon Skeet упоминает это в своем ответе: «.. В частности, вызов переопределенного метода из конструктора - это рецепт для трудно понятного кода и труднодоступных ошибок ». Но я не думаю, что последствия этой проблемы достаточно подчеркнуты. ]]

Конструкторы должны быть осторожны при утечке this до того, как экземпляр будет полностью инициализирован. Хотя предыдущее правило касалось методов внутри класса и подклассов, обращающихся к ivars, вы также должны будьте осторожны (даже окончательные / частные) методы, передающие this другим классам и служебным функциям до того, как this будет полностью инициализирована. Чем больше не закрытых, переопределяемых методов, вызываемых конструктором, тем выше риск утечки this.


Некоторые ссылки на конструкторы, вызывающие нефинансовые, не частные методы:

https://www.securecoding.cert.org/confluence/display/ java / MET05-J. + Обеспечить +, что + конструкторы + do + not + call + overridable + methods

http://www.javaworld.com/article/2074669/ core-java / java-netbeans - overridable-method-call-in-constructor.html

http://www.javaspecialists.eu/archive/Issue210.html

25
ответ дан Bert F 3 September 2018 в 17:17
поделиться

Я тоже не возражаю, и у меня нет сильной префы [и не придерживайтесь строгих стандартов], просто используйте свое мнение. Но если вы идете с сеттерами, любой, кто переопределяет класс, должен знать, что объект не может быть полностью создан. При этом убедитесь, что дополнительный код в сеттерах не может опубликовать ссылку this.

Сеттеры могут быть полезны для стандартных проверок диапазона и т. Д., Поэтому дополнительный код для проверки ввода не требуется. Опять-таки использование сеттеров немного грязнее.

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

На самом деле c-tor является одним из 3 возможных способов создания объекта (сериализация + клон - это другие 2), некоторые переходные состояния, возможно, придется обрабатывать вне c-tor, поэтому вы все еще есть, что задуматься о полях против сеттеров. (Изменить, есть еще одна половина: небезопасно, но это то, что использует сериализация)

0
ответ дан bestsss 3 September 2018 в 17:17
поделиться

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

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

1
ответ дан gbvb 3 September 2018 в 17:17
поделиться

Существует одна причина, по которой наши стандарты кодирования требуют использования аксессуаров (которые также могут быть частными). Если вы быстро захотите узнать, какой код меняет поле, вы просто вызываете иерархию вызовов для сеттера в Eclipse!

Это огромная экономия времени в кодовой базе, которая достигла 2 миллионов строк кода, а также облегчает рефакторинг.

1
ответ дан Jochen Bedersdorfer 3 September 2018 в 17:17
поделиться

Мое предпочтение заключается в том, чтобы установить их непосредственно в конструкторе по нескольким причинам. Во-первых, что-то вроде this.x = x; так же ясно, если не больше, чем вызов отдельного метода, который делает то же самое. Во-вторых, метод может быть потенциально переопределен, если он не будет помечен как окончательный, а вызов потенциально переопределенных методов из конструктора - это большое значение no-no в моей книге. В-третьих, большинство методов обычно предполагают, что объект уже завершен, когда они выполняются, а не на полпути к его построению. Хотя это не должно вызывать каких-либо проблем в этом простом случае, в более сложных случаях это может вызвать серьезные тонкие ошибки, требующие возраста для отслеживания.

Основной аргумент в пользу использования сеттеров / геттеров во всем мире состоит в том, что это означает вы можете переименовать поле, просто изменив его имя в 3-х местах, его определение, методы getter / setter, и все должно компилироваться и быть в порядке. На мой взгляд, этот аргумент недействителен в наши дни, поскольку любая достойная современная среда IDE переименует все вхождения такого поля с помощью простого сочетания клавиш.

0
ответ дан Michael Berry 3 September 2018 в 17:17
поделиться

Я редко это делаю, и из-за этого у меня никогда не было проблемы. Он также может иметь непреднамеренные последствия, особенно если ваши сеттеры переопределены в подклассе или если ваши сеттеры увольняют дополнительные вызовы методов, которые могут быть неприменимы во время инициализации.

2
ответ дан Stewart Murrie 3 September 2018 в 17:17
поделиться

Вызов любых методов public , static , non-final в конструкторе, зависит от вас, но наилучшей практикой является никогда не вызывать такие методы внутри конструктора, потому что эти методы могут быть переопределены в подклассах и на самом деле будет вызываться только переопределенная версия этих методов (если вы используете полиморфное поведение).

Например:

public class Foo {

public Foo() {
    doSmth(); // If you use polymorphic behavior this method will never be invoked
}

public void doSmth() {
    System.out.println("doSmth in super class");
}

public static void main(String[] args) {
    new Bar(200);
}
}

class Bar extends Foo {

private int y;;

public Bar(int y) {
    this.y = y;
}

@Override
public void doSmth() { // This version will be invoked even before Barr object initialized
    System.out.println(y);
}

}

Он будет печатать 0.

Для подробных сведений читайте Брюс Эккель «Мышление в Java» глава «Полиморфизм»

0
ответ дан TimurJD 3 September 2018 в 17:17
поделиться

Если ваш сеттер делает что-то более сложное, чем this.x = x, я бы просто установил переменную напрямую. Параметр отображает непосредственно вашу переменную экземпляра, и для меня это более увлекательно.

1
ответ дан Tyler Holien 3 September 2018 в 17:17
поделиться
Другие вопросы по тегам:

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