1

I need to know if this kind of constructor chain calls is possible in java? I'm extending base JButton class and I need first to initialize super variables then initialize my class with default constructor.

public CustomButton(){
    try {
        URL inp = CustomButton.class.getResource("/icons/noa_en/buttonBackground.png");
        background = ImageIO.read(inp);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public CustomButton(ImageIcon img){
    super(img);
    this();
}

or :

public CustomButton(ImageIcon img){
    this();
    super(img);
}
armin
  • 1,985
  • 6
  • 38
  • 52
  • Have u tried doing it? what is the result? – Juned Ahsan Nov 06 '13 at 10:16
  • yes in both cases it gives me "constructor call must be the first statement in a constructor".I'm using eclipe IDE. – armin Nov 06 '13 at 10:17
  • It is,but still gives me the same error.Try it first if you don't believe me. – armin Nov 06 '13 at 10:19
  • @armin this or super should be first line,you can not call both – SpringLearner Nov 06 '13 at 10:20
  • That would cause big problems, because this() would also call the super method. – MTilsted Nov 06 '13 at 10:21
  • @MTilsted be as it may,still it should be possible,if you look at pobrelkey answer he is practically doing the thing I asked but with just simple hack. – armin Nov 06 '13 at 10:25
  • @armin You don't need to duplicate call to `setup` method in each constructor. Please see my answer – kiruwka Nov 06 '13 at 10:33
  • @kiruwka thanks but this solution of yours has very limited application,suppose I wanted to make path to the image an input variable in one of the constructors.with your solution,there is no way this would be possible. – armin Nov 06 '13 at 12:07
  • @armin I don't see any problem here. You can always create constructor with parameters you need and inside the constructor override path to image value prior set in `initializer` block. BTW, how would you do that with accepted solution ? – kiruwka Nov 06 '13 at 12:35
  • @kiruwka your solution is static initialization,it's initialized before constructor,so the thing you said can't be done.I don't understand you question,the solution that I accepted is perfectly valid. – armin Nov 07 '13 at 05:04
  • @armin My solution is NOT 'static initialization`. `Static initialization` is very different, it uses `static` keyword before `initializer` block. However `instance` (i.e. `per-object` `initializer`) is a block of code executed before each constructor. It is designed specifically to be shared between constructors and to avoid constructors calling additional `init/setup` methods. I recommend that you to read [this](http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html) java tutorial. See `Initializing Instance Members`. Hope that helps – kiruwka Nov 07 '13 at 08:07
  • @armin I also updated example in my answer to make it more clear – kiruwka Nov 07 '13 at 08:19

6 Answers6

7

You can only call another constructor as your very first act within a constructor. So as you want to call different superclass constructors in the two constructors of your class, you'd have to refactor out the common code into a separate method:

public CustomButton() {
    // implicitly calls super() here
    setup();
}
public CustomButton(ImageIcon img) {
    super(img);
    setup();
}
private void setup() {
    // your init code
}
pobrelkey
  • 5,853
  • 20
  • 29
  • well,this is possibly the best solution so far,but still setup() would have to be repeated in all my constructors.also why calling both constructors in one is not possible in java?it doesn't violate any OOP rules. – armin Nov 06 '13 at 10:22
  • For alternative formulations, and some advice on multiple constructors in Java, have a look at [this question](http://stackoverflow.com/questions/581873/best-way-to-handle-multiple-constructors-in-java) – Alan Nov 06 '13 at 10:24
1

you can not call this

public CustomButton(ImageIcon img){
    super(img);
    this();
}

because super() or this will be first line

So you can not call super() or this() simultaneously

SpringLearner
  • 13,738
  • 20
  • 78
  • 116
1

You can always use instance initializing block as replacement of private init() method.
This way you will not need to duplicate call to init() in all constructors. And this block will be called for each constructor after super() constructor is finished. Please see example below :

class Parent {
    Parent(String s) {
        System.out.println("parent constructor");
    }
}

class Child extends Parent {
    int x, y, z;
    {
        // do object initialization here
        // whatever you do in your setup() method you can do here
        // this block is executed before each constructor of Child class
        x = 1; y = 2; z = 3; // assign default values
        System.out.println("Child object initialization");
    }

    Child(int new_x) {
        super("parent");
        System.out.println("Child constructor");
        // do some specific initialization
        x = new_x;
    }

    public static void main(String... args) {
        Child c = new Child(3); // prints
        // parent constructor -> Child object initialization -> Child constructor
        System.out.println(c.x); // 3
    }
}

Hope that helps.

kiruwka
  • 9,250
  • 4
  • 30
  • 41
0

In a constructor, you can only call super() or this() constrcutor. If you don't provide anything, then there will be an implicit call to super()

Prasad Kharkar
  • 13,410
  • 5
  • 37
  • 56
  • You say we cannot call super(..) or this(..) with arguments? – Gyro Gearless Nov 06 '13 at 10:17
  • No it gives me "constructor call must be the first statement in a constructor".don't know why. – armin Nov 06 '13 at 10:20
  • my point is, you can only call one other constructor. It could be either super constructor or this constructor. There is no problem regarding arguments. – Prasad Kharkar Nov 06 '13 at 10:20
  • @PrasadKharkar thanks but my question is how to call both not just one. – armin Nov 06 '13 at 10:23
  • @armin As per my knowledge, java does not allow what you want. What you can do is put the login in a method which you want to be executed when you call multiple constructors and call that method. – Prasad Kharkar Nov 06 '13 at 10:25
0

You can only call one constructor from the constructor and it should be the first line. You can call first this constructor and then simply call super constructor from the called constructor.

Check this:

class Parent {

    public Parent() {
        System.out.println("Parent: No args constructor called");
    }
}

public class Child extends Parent{
    String demo;

    public Child(String demo) {
        super();
        this.demo = demo;
        System.out.println("Child: Single arg constructor called");
    };

    public Child() {
        this("hello");
        System.out.println("Child: No arg constructor called");
    }

    public static void main(String args[]) {
        Child demo = new Child();
    }


}

Output:

Parent: No args constructor called

Child: Single arg constructor

called Child: No arg constructor called

Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136
0

this() & super() can only be called in the first line of the constructor.
This means that you can either call this() or super() because only one of these can take the first line.

If you don't mention this() or super() the compiler will call super() (with no arguments).

I would solve your problem by doing something like this:

private void init()
{
    try {
            URL inp = CustomButton.class.getResource("/icons/noa_en/buttonBackground.png");
            background = ImageIO.read(inp);
        } catch (IOException e) {
            e.printStackTrace();
    }
}

public CustomButton()
{
    init();
}

public CustomButton(ImageIcon img){
    super(img);
    init()
}

UPDATE:

Notice the code you provided:

public CustomButton(){
    super();    // This gets automatically added to the constructor
    try {
        URL inp = CustomButton.class.getResource("/icons/noa_en/buttonBackground.png");
        background = ImageIO.read(inp);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Notice the super() in CustomButton(). So in this case, it would mean that:

public CustomButton(ImageIcon img){
    super(img);
    this();
}

super() is being called twice, once by CustomButton() and once by CustomButton(ImageIcon img) which could lead to unexpected results depending on the constructors of JButton

It is for this reason, that Java expects this() or super() to take the first line.

galdin
  • 12,411
  • 7
  • 56
  • 71