Должен ли я инициализировать переменную внутри конструктора или внешнего конструктора

Когда я использую Java на основе моих знаний на С++, я люблю инициализировать переменную следующим образом.

public class ME {
    private int i;

    public ME() {
         this.i = 100;
    }
}

Спустя некоторое время я меняю привычку на

public class ME {
    private int i = 100;

    public ME() {
    }
}

Я столкнулся с другим исходным кодом, некоторые используют 1-е соглашение, другие используют 2-е соглашение.

Могу ли я узнать, какое соглашение вы все рекомендуете, и почему?

Ответ 1

Я нахожу второй стиль (декларация + инициализация за один раз) выше. Причины:

  • Это ясно показывает, как инициализируется переменная. Как правило, при чтении программы и пересечении переменной вы сначала переходите к ее объявлению (часто автоматически в IDE). Со стилем 2 вы сразу увидите значение по умолчанию. В стиле 1 вам также нужно посмотреть на конструктор.
  • Если у вас несколько конструкторов, вам не нужно повторять инициализации (и вы не можете их забыть).

Конечно, если значение инициализации различно в разных конструкторах (или даже вычислено в конструкторе), вы должны сделать это в конструкторе.

Ответ 2

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

Например, во втором фрагменте вы можете удалить конструктор и получить более четкий код.

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

class String
{
    char[] arr/*=char [20]*/; //Here initializing char[] over here will not make sense.
    String()
    {
        this.arr=new char[0];
    }
    String(char[] arr)
    {
        this.arr=arr;
    }
}

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

FYI другой вариант для инициализации без использования конструктора:

class Foo
{
    int i;
    static int k;

    //instance initializer block
    {
        //run every time a new object is created
        i=20;
    }

    //static initializer block
    static{
        //run only one time when the class is loaded
        k=18;
    }    
} 

Ответ 6

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

Ответ 7

Я рекомендую инициализировать переменные в конструкторах. Вот почему они существуют: чтобы ваши объекты были правильно сконструированы (инициализированы).

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

Ответ 8

Я думаю, что оба правильные программы мудры,

Но я думаю, что ваш первый вариант более корректен объектно-ориентированным образом, потому что в конструкторе возникает объект, и именно тогда инициализируется переменная.

Я думаю, что это конвенция "по книге", но она открыта для обсуждения.

Wikipedia

Ответ 9

Оба варианта могут быть правильными в зависимости от вашей ситуации.

Очень простой пример: Если у вас есть несколько конструкторов, все из которых инициализируют переменную одинаково (int x = 2 для каждого из них). Имеет смысл инициализировать переменную при объявлении, чтобы избежать избыточности.

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

Ответ 10

Это может зависеть от того, что вы инициализируете, например, вы не можете просто использовать инициализацию поля, если задействовано проверочное исключение. Например, следующее:

public class Foo {
    FileInputStream fis = new FileInputStream("/tmp"); // throws FileNotFoundException
}

приведет к ошибке времени компиляции, если вы также не включите конструктор, объявляющий, что проверенное исключение, или расширьте суперкласс, который делает, например:

public Foo() throws FileNotFoundException {} 

Ответ 11

Я бы сказал, это зависит от дефолта. Например

public Bar
{
  ArrayList<Foo> foos;
}

Я сделал бы new ArrayList вне конструктора, если я всегда предполагаю, что foos не может быть нулевым. Если Bar является допустимым объектом, не заботясь, если foos имеет значение null или нет, я бы поместил его в конструктор.

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