19

I need to call a method after the constructor has ended, and I have no idea what is the better approach.

I have this class:

class A {
    public A() {
        // ...
    }
        
    public void init() {
        // call after the constructor
    }
}

How do I call init() after the class A has been created?

mikelplhts
  • 1,181
  • 3
  • 11
  • 32
  • 1
    Some answers seem to be assuming that the init can simply be moved inside the constructor, but I assume that whatever it is doing is *not* appropriate to be done in the constructor (such as registering listeners, which would then have a chance to see a partially constructed object), otherwise there would be no need for the question. – David Conrad Dec 12 '14 at 22:36

6 Answers6

21

You either have to do this on the client side, as so:

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

or you would have to do it in the end of the constructor:

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

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

The second way is not recommended however, unless you make the method private or final.


Another alternative may be to use a factory method:

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;
    }
}

Related questions:

Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • If `init()` starts a new thread or shares its `this` reference with another class that may access the reference from another thread, you should _not_ call it in the constructor. If you do, you'll have a data race. – yshavit Dec 12 '14 at 22:35
  • The same problem applies if you do it directly in the constructor. There's no difference if you delegate part of the construction to the `init` method. What *is* a problem is when the `init` method may be overridden by subclasses. – aioobe Dec 12 '14 at 22:37
  • You probably want to make the `init` method private as well if you go the static factory method route. It does make a difference if the issue is sharing the `this` reference with other threads, since once the constructor completes the class's invariants are presumably ensured and particularly any final fields will be guaranteed to be visible from other threads. – David Conrad Dec 12 '14 at 22:40
  • @aioobe The fact that inlining it also has that bug doesn't detract from my comment, imho. `init()` methods often publish `this` or spin off threads -- that's commonly _why_ they're separate methods as opposed to just being in the constructor. Given that the construct-than-init pattern has a relatively high correlation with init-does-thread-stuff, I thought it'd be helpful to point that danger out explicitly. – yshavit Dec 12 '14 at 22:50
  • @DavidConrad This may be what you're getting at, but just to make sure... if `this` leaks out during the constructor, the final fields are _not_ guaranteed to be be visible from other threads (which is exactly why you shouldn't let it leak out). – yshavit Dec 12 '14 at 22:51
  • If `this` leaks out from the constructor I'd say you have more problems then that. Fields may not be initialized even as seen from the *same* thread. – aioobe Dec 12 '14 at 22:53
  • I was suggesting that the `init` method should be private just because it probably doesn't make any *sense* to have others calling it later on. If it adds listeners, or starts threads, it's presumably something you want done once-and-only-once, so why expose that functionality to the world, just so they can call it at inappropriate times? – David Conrad Dec 12 '14 at 22:56
  • @aioobe Sure, but then you naively fix them one by one -- single-thread operations are deterministic, after all -- and declare the bugs worked out. One day you're on a 24-node machine under high CPU load and boom, it blows up in a way you can't reproduce even after a week of pouring over the code. I'd trade one multithreaded bug for 10 single-threaded ones most days of the week. – yshavit Dec 12 '14 at 22:56
  • That of course depends on the application. It could very well be the case that it "resets" the object, which might be useful to be able to do from the outside. – aioobe Dec 12 '14 at 22:57
  • 1
    Well, I guess we just won't see eye to eye on the relevance of my comment, then. So I'll just leave it as a note to the OP: if your `init()` method exposes `this` to anyone (another thread, another class, etc) you're exposing yourself to subtle data race bugs. Do so at your own peril. – yshavit Dec 12 '14 at 22:58
  • @yshavit, your reply to *"leaking `this` has more problems than multithreading problems"* is *"doesn't matter much, single threaded problems are easy"*. Well, the problem is that leaking `this` from the constructor is *error prone* and even if you solve all problems of leaking `this` in the current code base, you'll have a harder time maintaining that code base. What I'm saying is, don't leak `this` from the constructor, even if you're in a single threaded environment. – aioobe Dec 12 '14 at 23:00
  • Um, okay, sure. But again, since `init()` method are very often written _because_ they expose `this`, I think it's especially important to explicitly point out the problems of exposing `this` from the constructor when suggesting (as your answer does) that you can just call `init()` at the end of the constructor. That's all I've been saying from the start, really. – yshavit Dec 12 '14 at 23:02
4

You will need a static factory method to construct the object, call the init method, and finally return the object:

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

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

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

Notice I have made the constructor and the init() method private, so that they can only be accessed by the factory method. Client code would make objects by calling A.create() instead of calling the constructor.

David Conrad
  • 15,432
  • 2
  • 42
  • 54
  • 1
    Good idea, but you don't need a factory, if the stuff is private. You could simply call it at the end of the constructor. But you can use a factory as a good solution, if the method and constructor are protected, to ensure, that overriding the constructor does not result in a missing init() call. **EDIT** of course, if the constructor is protected and the class is abstractable, you need a more generic factory method - forgot to mention that. – UniversE Dec 12 '14 at 22:37
  • 1
    @UniversE No, you can't simply call it at the end of the constructor. Java makes special guarantees about the visibility of final fields after the constructor has completed. If you pass a reference to the object to another thread, it could see default values for those fields, which cannot happen after the constructor has finished. – David Conrad Dec 12 '14 at 22:42
  • But if you call it at the end of the constructor, the method would execute on the same thread, and there would be no visibility issues. – aioobe Jun 25 '16 at 06:50
  • @aioobe if you call it at the end of the constructor, and `init()` lets a reference to `this` escape, another thread could examine the object *before the constructor finishes*. See yshavit's comments on another answer to this question. – David Conrad Jun 25 '16 at 15:03
  • Letting `this` escape before the object has been fully initialized is a terrible idea, regardless if it's done from the constructor or from an init method, and regardless if there are multiple threads or not. – aioobe Jun 25 '16 at 15:35
  • @aioobe which it is why you would do it only after the object has been fully initialized, such as from a method called by a static factory method. Hence my answer. – David Conrad Jun 25 '16 at 15:40
1

What did you so far? Are you looking something like this?

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

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

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

    a.init();
}
AngularLover
  • 364
  • 1
  • 12
1

I pick up some ideas and provide an abstractable solution:

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;
        }
    }
}
UniversE
  • 2,419
  • 17
  • 24
1

If you want to call method BEFORE constructor you can use initializer block. https://www.geeksforgeeks.org/g-fact-26-the-initializer-block-in-java/

class A {
    { 
        init() 
    }

    public A() {
        //todo
    }

    private final void init() {
       //todo
    }
}
acsadam0404
  • 2,711
  • 1
  • 26
  • 36
-2

Why not this :

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

    public void init() {
        //Call after the constructor
    }
}
Nico
  • 6,395
  • 4
  • 25
  • 34
  • The constructor is not complete in this case. The constructor completes AFTER this.init() is run. In general, it is not good practice to run methods using this inside its own constructor because the constructor is not fully created. Usually this messes things up when you have multiple threads. – George Xavier May 15 '19 at 04:26