2014-12-12 4 views
9

Мне нужно вызвать метод после того, как конструктор закончился, и я понятия не имею, как это сделать. У меня есть этот класс:Вызвать метод после завершения конструктора

Class A { 
    public A() { 
     //... 
    } 

    public void init() { 
     //Call after the constructor 
    } 
} 
+0

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

ответ

11

Вы должны либо сделать это на стороне клиента, а так:

A a = new A(); 
a.init(); 

или вы должны сделать это в конце конструктора:

class A { 
    public A() { 
     // ... 
     init(); 
    } 

    public final void init() { 
     // ... 
    } 
} 

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


Другой альтернативой может быть использование фабричный метод:

class A { 
    private A() { // private to make sure one has to go through factory method 
     // ... 
    } 
    public final void init() { 
     // ... 
    } 
    public static A create() { 
     A a = new A(); 
     a.init(); 
     return a; 
    } 
} 

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

+0

Если 'init()' запускает новый поток или обменивается ссылкой 'this' с другим классом, который может получить доступ к ссылке из другого потока, вы не должны его вызывать в конструкторе. Если да, у вас будет гонка данных. – yshavit

+0

Такая же проблема возникает, если вы делаете это непосредственно в конструкторе. Нет никакой разницы, если вы делегируете часть конструкции методу 'init'. Что * * проблема, когда метод 'init' может быть переопределен подклассами. – aioobe

+0

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

0

Почему бы не так:

Class A { 
    public A() { 
     //... Do you thing 
     this.init(); 
    } 

    public void init() { 
     //Call after the constructor 
    } 
} 
1

Что вы до сих пор? Вы выглядите что-то вроде этого?

Class A { 
     public A() { 
      //... 
     } 

     public void init() { 
      //Call after the constructor 
     } 
    } 

    public static void main(String[] args) 
    { 
    A a = new A(); 

    a.init(); 
} 
3

Вам нужен статический фабричный метод для создания объекта, вызовите метод инициализации, и, наконец, вернуть объект:

class A { 
    private A() { 
     //... 
    } 

    private void init() { 
     //Call after the constructor 
    } 

    public static A create() { 
     A a = new A(); 
     a.init(); 
     return a; 
    } 
} 

Обратите внимание, я сделал конструктор и метод init() частного, так что к ним можно получить доступ только по заводскому методу. Клиентский код будет создавать объекты, вызывая A.create() вместо вызова конструктора.

+1

Хорошая идея, но вам не нужна фабрика, если материал закрыт. Вы можете просто вызвать его в конце конструктора. Но вы можете использовать завод как хорошее решение, если метод и конструктор защищены, чтобы гарантировать, что переопределение конструктора не приведет к отсутствию вызова init(). ** ИЗМЕНИТЬ **, конечно, если конструктор защищен и класс абстрагирован, вам нужен более общий заводский метод - забыл упомянуть об этом. – UniversE

+1

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

+0

Но если вы вызываете его в конце конструктора, метод будет выполняться в том же потоке, и не будет проблем с видимостью. – aioobe

1

я забрать некоторые идеи и обеспечить abstractable решение:

class A { 
    protected A() { 
     // ... 
    } 
    protected void init() { 
     // ... 
    } 
    public static <T extends A> T create(Class<T> type) { 
     try { 
      T obj = type.newInstance(); 
      obj.init(); 
      return obj; 
     } catch (ReflectiveOperationException ex) { 
      System.err.println("No default constructor available."); 
      assert false; 
      return null; 
     } 
    } 
} 
+0

Насколько я могу судить, это единственный ответ, который работает с наследованием. Или я ошибаюсь? –

Смежные вопросы