Соглашение о языке Java; геттеры / сеттеры

Public class Example {

    private int number;

    public Example(int number){
        this.number = number;
    }

    public int getNumber(){
        return number;
    }

    public void setNumber(int number){
        this.number = number;
    }

    public static void main(String[] args){
        Example e = new Example(5);

Что предпочтительнее при доступе к переменной внутри ее собственного класса; "e.number" или "e.getNumber()"?

Редактировать:
Я думаю, что самый важный вопрос: знает ли компилятор, что метод, который вы вызываете, является геттером или сеттером. Так будет e.setNumber(5); будь так же быстр, как e.number = 5;

12 ответов

Решение

Я бы сказал, что это зависит от ситуации. Если поле является чем-то простым, например, int и вряд ли изменится в будущем, я бы получил доступ к нему с помощью number и не getNumber(),

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

Мое эмпирическое правило: если есть какой-то отдаленный шанс, что я смогу извлечь выгоду из getNumber() я использую getNumber()иначе я использую number для ясности и краткости.

e.getNumber() это общий подход. Так get или же set + VariableName,

Вы также можете посмотреть ЗДЕСЬ.

this.number

В большинстве случаев они будут оптимизированы под тот же код, но смысл использования сеттеров / геттеров состоит в том, чтобы избежать изменения API в случае изменения реализации. Однако в классе вы не используете "API", но вы видите все внутренности и состояние.

Дополнительно вы можете использовать

numer += 5;

вместо

setNumber(getNumber() + 5);

Изменить: Конечно, вне класса он должен быть защищен с помощью getter/setter, так как вы можете изменить внутреннее представление и обеспечить обратную совместимость, переопределив их в терминах представления нового состояния.

Изменить 2: main немного особенным. Я бы сказал, что main должно быть минимально возможным - создать несколько объектов и вызвать максимум один или два метода - следовательно, он не должен присваивать переменные и должен рассматриваться как "внешняя" часть. С другой стороны, некоторые предоставляют методы испытаний в main который может потребовать прямого доступа к состоянию. Поэтому, если вы можете, вы не должны напрямую обращаться к полям в main,

По скорости в main в любом случае это не имеет значения, поскольку запуск JVM компенсирует любые затраты. Реальная разница будет во внутренних циклах, в которых JIT позаботится об этом.

Чтобы ответить на ваш последний вопрос, посмотрите на этот пример,

Java-код:

public void test2() {
    setNumber(getNumber() + 1);
}

Байт-код:

public test2()V
   L0
    LINENUMBER 47 L0
    ALOAD 0
    ALOAD 0
    INVOKEVIRTUAL com/test/ByteCodeTester.getNumber()I
    ICONST_1
    IADD
    INVOKEVIRTUAL com/test/ByteCodeTester.setNumber(I)V
   L1
    LINENUMBER 48 L1
    RETURN
   L2
    LOCALVARIABLE this Lcom/test/ByteCodeTester; L0 L2 0
    MAXSTACK = 3
    MAXLOCALS = 1

Как видите, байт-код все еще выполняет 2 вызова метода. Таким образом, в этом случае компилятор не воспринимает это иначе.

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

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

Однако опасность состоит в том, что, поскольку они являются полноценными вызовами методов, они могут буквально делать что угодно - запускать процесс, загружать файл, выполнять дорогостоящее задание и т. Д. Это, конечно, глупо в контексте метода получения / установки, но это нечто чтобы избежать Я также слышал о коде, который выполняет большую часть того, что он должен делать в методах получения / установки, не имея реальных методов!!

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

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

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

JVM будет оптимизировать вызов метода установщика всякий раз, когда это будет безопасно (т. Е. Практически в любом случае, когда у вас возникнет искушение просто использовать поле). Так что для производительности это не должно иметь значения, если вы не используете JVM, которая не выполняет JIT-компиляцию (например, Dalvik). Фактически, вы можете связывать вызовы методов на нескольких уровнях, и JVM оптимизирует его до простого доступа к полю, когда он фактически запускает его на оборудовании.

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

Попрощайтесь с многопоточностью с помощью this.number=.. не говоря уже о возможной необходимости контроля над тем, что может быть внутри this.number. С помощью setNumber() Java завершает, что этот метод может быть окончательным и может сделать много с оптимизацией, так что вы не сможете почувствовать разницу...

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

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

Тем не менее, существуют исключения, хотя по большей части они являются более личными предпочтениями, чем общие рекомендации. Я получу доступ к переменным-членам напрямую:

  1. При реализации того, что я считаю "низкоуровневой" функциональностью (а это абсолютно субъективно, в моем случае я считаю, #equals(), #hashCode(), #toString() и тому подобное "низкий уровень"). Я не думаю, что для этого есть очень веские технические причины, мне просто кажется, что это лучше.
  2. Если слишком неудобно использовать сеттеры / геттеры (например, num ++ против setNumber(getNumber() + 1) как кто-то еще указал).
  3. Если мой геттер выполняет какую-то дополнительную работу, и в моем конкретном случае я не хочу такого поведения.
  4. ... И есть, вероятно, другие случаи, которые я пропустил...

Номер, если он используется в том же классе. И e.getnumber в любых подклассах или в любом месте за пределами

Число

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

Изменить: О, вы хотите использовать его в главной функции внутри класса? Тогда ofc e.getNumber(), как сказал другой парень.

Другие вопросы по тегам