Подтвердить что ты не робот

Возможно ли выполнить вычисление перед супер() в конструкторе?

Учитывая, что у меня есть класс Base, у которого есть единственный конструктор аргументов с объектом TextBox в качестве аргумента. Если у меня есть класс Simple следующего вида:

public class Simple extends Base {
  public Simple(){
    TextBox t = new TextBox();
    super(t);
    //wouldn't it be nice if I could do things with t down here?
  }
}

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

public class Simple extends Base {
  public Simple(){
    super(new TextBox());
  }
}

Почему это разрешено, но первый пример - нет? Я могу понять, что нужно сначала настроить подкласс и, возможно, не позволить создавать объектные переменные до вызова суперконструктора. Но t - явно метод (локальная) переменная, так почему бы не позволить это?

Есть ли способ обойти это ограничение? Есть ли хороший и безопасный способ держать переменные в вещах, которые вы могли бы создать, прежде чем звонить супер, но ПОСЛЕ того, как вы вошли в конструктор? Или, в более общем плане, позволяя выполнить вычисление до того, как супер действительно вызывается, но внутри конструктора?

Спасибо.

4b9b3361

Ответ 1

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

public class Simple extends Base {
    private Simple(TextBox t) {
        super(t);
        // continue doing stuff with t here
    }

    public Simple() {
        this(new TextBox());
    }
}

Для более сложных вещей вам необходимо использовать factory или статический метод factory.

Ответ 2

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

Используйте частный статический метод внутри вашего класса, который возвращает аргумент супер-конструктора и делает свои проверки внутри:

public class Simple extends Base {
  public Simple(){
    super(createTextBox());
  }

  private static TextBox createTextBox() {
    TextBox t = new TextBox();
    t.doSomething();
    // ... or more
    return t;
  }
}

Ответ 3

требуется на этом языке, чтобы гарантировать, что суперкласс надежно сконструирован первым. В частности, "Если конструктор явно не вызывает конструктор суперкласса, компилятор Java автоматически вставляет вызов конструктору без аргументов суперкласса".

В вашем примере суперкласс может полагаться на состояние t во время построения. Вы всегда можете попросить копию позже.

Здесь подробно обсуждается .

Ответ 4

Причина того, что второй пример разрешен, но не первый, скорее всего, сохранит язык в порядке и не вводит странные правила.

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

Ответ 5

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

В вашем случае чаще всего используется getter, который позволяет вам получить доступ к параметру, предоставленному super(). Поэтому вы должны использовать это:

super( new TextBox() );
final TextBox box = getWidget();
... do your thing...