Соглашение о языке Java; геттеры / сеттеры - PullRequest
2 голосов
/ 19 мая 2010
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 ]

4 голосов
/ 19 мая 2010

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

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

3 голосов
/ 19 мая 2010

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

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

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

3 голосов
/ 19 мая 2010
this.number

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

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

numer += 5;

вместо

setNumber(getNumber() + 5);

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

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

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

1 голос
/ 19 мая 2010

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

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 вызова метода. Таким образом, в этом случае компилятор не относится к этому по-другому.

1 голос
/ 19 мая 2010

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

0 голосов
/ 19 мая 2010

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

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

0 голосов
/ 19 мая 2010

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

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

0 голосов
/ 19 мая 2010

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

0 голосов
/ 19 мая 2010

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

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

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

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

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

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

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

...