Есть ли какая-то польза от установки переменных экземпляра при вызове его конструктора, а не в конструкторе? - PullRequest
3 голосов
/ 14 июня 2009

Например:

public class Foo {
    private int bar = 42;

    Foo() {}
}

против

public class Foo {
    private int bar;

    Foo() {
        bar = 42;
    }
}

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

public class Foo {
    private int bar = 42;

    Foo() {}

    Foo(int in) {
        bar = in;
    }
}

против (в любом случае вы устанавливаете его только один раз)

public class Foo {
    private int bar;

    Foo() {
        this(42);
    }

    Foo(int in) {
        bar = in;
    }
}

Я что-то упустил? Есть ли какая-то внутренняя ценность в том, чтобы делать это так или иначе?

Редактировать

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

Редактировать 2

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

Ответы [ 5 ]

11 голосов
/ 14 июня 2009

Два метода эквивалентны. С учетом сказанного я добавлю две вещи:

  1. Это, как правило, больше проблем с конечными переменными, потому что, очевидно, вы можете установить их только один раз, как в третьем фрагменте; и
  2. Попробуйте соединить ваши конструкторы вместе.

On (2) Я думаю, что это лучшая версия:

public class Foo {
    private int bar;

    Foo() {
        this(42);
    }

    Foo(int in) {
        bar = in;
    }
}

Объединяя конструкторы в цепочку, вы можете получить стандартные значения по умолчанию приятным СУХИМЫМ способом (не повторяйтесь), особенно когда имеете дело с несколькими параметрами, которые могут иметь аргументы по умолчанию, различными разрешенными типами параметров и нетривиальной инициализацией. В идеале только один или два ваших конструктора должны иметь в себе значительную логику. Остальные должны просто соединиться с другим конструктором.

Если вы хотите сделать класс неизменным (как говорит Джош Блох, поддержите неизменность), тогда:

public class Foo {
    private final int bar;

    Foo() {
        this(42);
    }

    Foo(int in) {
        bar = in;
    }
}

Наконец, возможно, стоит сделать статическую конечную константу 42 (частной или общедоступной, в зависимости от ситуации).

2 голосов
/ 14 июня 2009

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

Но Java предоставляет нам блок инициализатора. Блоки инициализатора копируются в каждый конструктор компилятором. Так что, если вы беспокоитесь о несовместимости конструкторов, вы можете сделать это:

 public class Foo {
   private int bar;

   //initializer block
   {
      //initializing code here
   }

   Foo() {

   }
 }

Второй вариант, который у вас есть, - это цепочка конструкторов, как описано в cletus.

0 голосов
/ 05 октября 2017

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

Вывод приведенного ниже кода:

early = 42
late = 0

Вот код теста:

class Test {

    private static class Base{

        Base() {
            doInConstructor();
        }

        protected void doInConstructor() {

        }
    }

    private static  class Derived extends Base {
        final int early = 42;
        final int late;

        Derived() {
            late = 84;
        }

        protected void doInConstructor() {
            super.doInConstructor();
            System.out.println("early = " + early);
            System.out.println("late = " + late);
        }
    }

    public static void main(String[] args) {
        new Derived();
    }
}
0 голосов
/ 14 июня 2009

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

Мой собственный (ненаучный) опыт работы с унаследованным Java-кодом заключается в том, что, если имеется более двух конструкторов и более двух полей, в 80% случаев что-то будет неправильно инициализировано.

0 голосов
/ 14 июня 2009

лично я предпочитаю первый способ, так как более понятно, каково изначально значение var

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