Я должен инстанцировать переменных экземпляра на объявлении или в конструкторе?

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

Как описано в документации , это должно работать:

Pkg.add(PackageSpec(name = "GDAL", version = "0.1.2"))
Pkg.pin(PackageSpec(name = "GDAL", version = "0.1.2"))

Или в режиме REPL Pkg (])

pkg> add GDAL@0.1.2
pkg> pin GDAL@0.1.2

. по умолчанию закрепляет текущую используемую версию, поэтому, если вы уже указали версию в add, вы можете оставить ее для pin. Обратное также работает, то есть добавить последнюю версию, а затем pin более старую.

Кроме того, последняя версия GDAL.jl, v0.2.0, должна нормально работать на julia 0.7. Если это не так, пожалуйста, отправьте вопрос:)

217
задан Jeroen Vannevel 1 September 2014 в 03:13
поделиться

9 ответов

  • Разницы нет - инициализация переменной экземпляра фактически помещается компилятором в конструктор(ы).
  • Первый вариант более читабельный.
  • Обработка исключений с первым вариантом невозможна.
  • Дополнительно имеется блок инициализации, который также помещается компилятором в конструктор(ы):

    {
     a = новая A();
    }
    

Проверьте пояснения и советы солнца

из этого учебника :

Декларации полей, однако, не являются частью какого-либо метода, поэтому они не могут выполняться в том виде, в каком они есть. Вместо этого компилятор Java автоматически генерирует код инициализации поля экземпляра и помещает его в конструктор или конструкторы класса. Код инициализации вставляется в конструктор в том порядке, в котором он появляется в исходном коде, что означает, что инициализатор поля может использовать начальные значения полей, объявленных перед ним.

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

ExpensiveObject o;

public ExpensiveObject getExpensiveObject() {
    if (o == null) {
        o = new ExpensiveObject();
    }
    return o;
}

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

.
259
ответ дан 23 November 2019 в 04:16
поделиться
    class MyClass extends FooClass {
    String a = null;

    public MyClass() {
        super();     // Superclass calls init();
    }

    @Override
    protected void init() {
        super.init();
        if (something)
            a = getStringYadaYada();
    }
}

Относительно вышеупомянутого,

String a = null;

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

class MyClass extends FooClass 
{
    String a;
    {
        if( a==null ) a="my custom default value";
    }
    ...
0
ответ дан 23 November 2019 в 04:16
поделиться

Второй пример - ленивая инициализация. Первый - более простая инициализация, они по сути одни и те же.

0
ответ дан 23 November 2019 в 04:16
поделиться

Я думаю, что пример 2 предпочтительнее. Я думаю, что лучшая практика - объявить вне конструктора и инициализировать в конструкторе.

.
1
ответ дан 23 November 2019 в 04:16
поделиться

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

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

Смотрите http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html для более детального ознакомления с инициализацией на Java (и для пояснения блоков инициализатора и других малоизвестных особенностей инициализации).

.
4
ответ дан 23 November 2019 в 04:16
поделиться

мое личное "правило" (почти никогда не нарушаемое) заключается в том, чтобы:

  • объявлять все переменные в начале блок
  • делает все переменные окончательными, если они не не может быть
  • объявить одну переменную на строку
  • никогда не инициализируйте переменную, где объявленное
  • только инициализировать что-то в конструктор, когда ему нужны данные от конструктор для выполнения initialization

So I would have code like:

public class X
{
    public static final int USED_AS_A_CASE_LABEL = 1; // only exception - the compiler makes me
    private static final int A;
    private final int b;
    private int c;

    static 
    { 
        A = 42; 
    }

    {
        b = 7;
    }

    public X(final int val)
    {
        c = val;
    }

    public void foo(final boolean f)
    {
        final int d;
        final int e;

        d = 7;

        // I will eat my own eyes before using ?: - personal taste.
        if(f)
        {
            e = 1;
        }
        else
        {
            e = 2;
        }
    }
}

So I'm always 100% defined where to look for variables declarations (в начале блока), and their assignments (as soon it makes sense after the declaration). Это тоже потенциально более эффективно, так как никогда не инициализируешь переменную значением, которое не используется (например, объявить и init vars, а затем бросить исключение перед половиной тех vars, которые должны иметь значение). Также вы не заканчиваете делать бессмысленную инициализацию (например, int i = 0; а потом, до использования "i", do i = 5;.

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

Ваш пробег может варьироваться.

14
ответ дан 23 November 2019 в 04:16
поделиться

Другим вариантом было бы использование Dependency Injection .

class A{
   B b;

   A(B b) {
      this.b = b;
   }
}

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

.
36
ответ дан 23 November 2019 в 04:16
поделиться

Оба метода приемлемы. Обратите внимание, что в последнем случае b=new B() может не инициализироваться, если присутствует другой конструктор. Думайте о коде инициализатора вне конструктора как об обычном конструкторе, и код будет выполнен.

1
ответ дан 23 November 2019 в 04:16
поделиться

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

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

public class A {
    private Properties properties;

    {
        try {
            properties = new Properties();
            properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
        } catch (IOException e) {
            throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
        }
    }

    // ...

}
7
ответ дан 23 November 2019 в 04:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: