简体   繁体   中英

call a method when an object is initializing

I'm extending from an abstract class named ChildClass , it has 4 constructors which should be implemented.
There is a set of general configuration common to all constructors.
I could abstract these tasks and call it in all constructors.
Is there anyway to call a specif method when an object is going to be initialized rather than calling it in all of the constructor signatures?

Since Java compiler must ensure a call to a constructor of the base class, you can place the common code in a constructor of your abstract base class:

abstract class BaseClass {
    protected BaseClass(/*put arguments here*/) {
        // Code that is common to all child classes
    }
}
class ChildClassOne extends BaseClass {
    public ChildClassOne(/*put arguments here*/) {
       super(arg1, arg2, ...);
       // More code here
    }
}

You can declare an instance method in the class which can be called from a constructor like this:

Class A{
  public A(){
     initialize();
  }

  public void initialize(){
     //code goes here
  }
}

This concept extends to abstract classes as well.

You could chain your constructors.

public class Test {

    public Test() {
        // Common initialisations.
    }

    public Test(String stuff) {
        // Call the one ^
        this();
        // Something else.
    }

You can then put your common code in the () constructor.

As already stated in the comment, one way to call common initialization code would be the use of this(...) , ie you'd call one constructor from another. The problem, however, is that this call would have to be the first statement of a constructor and thus might not provide what you want.

Alternatively you could call some initialization method (the most common name would be init() ) in all constructors and in a place that is appropriate (eg at the end of the constructor). There is one problem though: if a subclass would override that method it could create undefined situations where the super constructor calls the method and the method uses non-yet-initialized fields of the subclass. To mitigate that the method should not be overridable, ie declare it final or make it private (I'd prefer to have it final though because that's more explicit).

Depending on your needs there's a 3rd option: use the initializer block:

class Super {
  {
    //this is the initializer block that is called before the corresponding constructors 
    //are called so it might or might not fit your needs
  }
}

Here's an example combining all 3 options:

static class Super {
  {
    //called before any of the Super constructors
    System.out.println( "Super initializer" );
  }

  private final void init() {
    System.out.println( "Super init method" );
  }

  public Super() {
    System.out.println( "Super common constructor" );
  }

  public Super(String name) {
    this(); //needs to be the first statement if used
    System.out.println( "Super name constructor" );
    init(); //can be called anywhere
  }
}

static class Sub extends Super {
  {
    //called before any of the Sub constructors
    System.out.println( "Sub initializer" );
  }

  private final void init() {
    System.out.println( "Sub init method" );
  }

  public Sub() {
    System.out.println( "Sub common constructor" );
  }

  public Sub(String name) {
    super( name ); //needs to be the first statement if used, calls the corrsponding Super constructor
    System.out.println( "Sub name constructor" );
    init(); //can be called anywhere
  }
}

If you now call new Sub("some name") , you'll get the following output:

Super initializer
Super common constructor
Super name constructor
Super init method
Sub initializer
Sub name constructor
Sub init method

An alternative is to use an Initializer block .

Class A {
  {
    // initialize your instance here...
  }
  // rest of the class...
}

The compiler will make sure the initializer code is called before any of the constructors.

However, I would hesitate a bit to use this use this - perhaps only if there are no other alternatives possible (like putting the code in a base class).

If you can put the common code in one constructor and call it as the first instruction from the other constructors, it is the Java idiomatic way.

If your use case is more complex, you can call a specific method from the constructors provided it is private, final or static (non overidable). An example use case would be:

class Test {
    private final void init(int i, String str) {
        // do common initialization
    }
    public Test(int i) {
        String str;
        // do complex operations to compute str
        init(i, str);    // this() would not be allowed here, because not 1st statement
    }

    public Test(int i, String str) {
        init(i, str);
    }

}

Make a common method and assign it to instance variable. Another way of doing it.

import java.util.List;

public class Test {
     int i = commonMethod(1);

    Test() {
        System.out.println("Inside default constructor");
    }

    Test(int i) {
        System.out.println("Inside argument  Constructor ");
    }

    public int commonMethod(int i) {
        System.out.println("Inside commonMethod");
        return i;
    }

    public static void main(String[] args) {
        Test test1 = new Test();
        Test test2 = new Test(2);

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM