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

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

Но что, если переменные являются окончательными? Пример:

public class Test {

    public final int MY_INT;

    public Test(int myInt) {
        MY_INT = myInt;
    }

}

Будет ли это разрешено? Он скомпилирован и отлично работает, но считается ли он хорошим кодом?

Ответ 1

Это компилируется, но не считается хорошим кодом.

MY_INT нарушает соглашение об именах: имена со всеми шапками используются для переменных static final, также называемых "константами класса" (см. this и this, Руководство по стилю Google Java слишком). чтобы соответствовать соглашениям об именах, было бы лучше переименовать в myInt.

Рекомендуется использовать getter, чтобы скрыть детали реализации вашего класса. Интерфейсы содержат только методы, а не поля. Если вы разрешите другим классам ссылаться на это поле по имени, то вы теряете свободу позже менять имя или свое внутреннее представление.

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

(Благодаря @Sotirios Delimanolis для ссылок на руководство по кодированию, очень ценится!)

Ответ 2

Если клиент мог получить доступ к публичному полю в вашем вопросе до того, как ему присвоено значение (т.е. без вызова конструктора), будет очевидная проблема. В частности, это поле не могло иметь ожидаемого/правильного значения, когда клиент пытался получить к нему доступ. Тем не менее, как было отмечено в комментариях, вы не объявили Test.MY_INT с идентификатором static, что делает невозможным получение значения этой константы без первого вызова конструктора.

Следовательно, казалось бы разумным (с точки зрения неизменности) делать то, что вы делаете. Однако, с точки зрения "хорошего кода", вы (как говорили другие), заставляете себя и своих клиентов явно ссылаться на это значение по имени. Однако, если вы использовали геттер, и вам нужно было изменить имя MY_INT, сохраняя при этом цель константы одинаковой, ни вы, ни ваш клиент не должны были бы изменять что-либо за пределы реализации в Test.

Чтобы быть более явным, я предоставляю вашему классу геттер и приватизированную константу.

public class Test {

    private final int MY_INT;

    public Test(int myInt) {
        MY_INT = myInt;
    }

    public int getAssignedIntValue() {
        return MY_INT;
    }

}

Я получил бы присвоенное целочисленное значение следующим образом:

Test test = new Test(1);
// with your class
test.MY_INT;
// with the above class    
test.getAssignedIntValue();

Теперь, скажем, я переименовал MY_INT в myInt для соответствия соглашениям об именах. В обоих случаях я должен изменить все вхождения MY_INT в классе Test. Но разница между двумя реализациями становится ясна, когда мне нужно получить значение с новым именем константы:

// if this is the old code from above
Test test = new Test(1);
// I need to change this to test.myInt, or I get an ERROR!
test.MY_INT;
// since I didn't change the name of the getter, all is well
test.getAssignedIntValue();

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

Ответ 3

Ответы поставщика неполны (даже тот, который выбран как "ответ" ). Подумайте, что произойдет, если рассматриваемое поле представляет собой коллекцию или массив объектов. Хорошая практика состоит в том, чтобы сделать все поля частными и предоставить "получателям" для этих полей. Но более конкретно, ваш getter должен вернуть (неизменяемую) ссылку на поле (т.е. String), или защитную копию изменяемых полей (т.е. Массив объектов). Это связано с тем, что даже если вы не можете изменить базовый адрес рассматриваемого объекта, вы можете изменить внутренности объекта (массив или коллекцию), просто получив базовый адрес. Имейте в виду, что изменчивыми полями я не имею в виду только массивы или коллекции. Он применяется к любому изменяемому классу.

Возвращаясь к вопросу, есть геттеры ТРЕБУЕМЫЕ? Ответ - нет. ОДНАКО, если вы хотите иметь надежный код, вам лучше всего следовать этим лучшим практикам; даже если это просто для создания хороших привычек. Если вы регулярно практикуете их, вы не будете следовать передовым методам при кодировании (и, скорее всего, другие в вашем проекте тоже не будут).

Ответ 4

Да, вы можете. Пока вы не инициализируете эту переменную на уровне класса или других сеттерах.

Ответ 5

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

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

Вы нарушаете инкапсуляцию таким образом.