views:

122

answers:

4

I have the next code:

class Foo {

   public Foo (String param) { ... }
}

class Bar extends Foo {

   public Bar () {
      super (doSmth());
      ...
   }

   private static String doSmth () {
      //what I can NOT do here?
   }
}

I wonder is it safe? Are there any limitations about doSmth method?

+3  A: 

Bypassing the requirement is very unsafe because it would allow you to call a method on the base class before its constructor had been run. Only bad things can happen there. This is why Java (and most other sane languages force this to be done)

class Foo { 
  string m_field;
  public Foo(string param) {
    m_field = param;
  }
  public void Method() {
    // use m_field
  }
}

class Bar extends Foo { 
  public Bar() {
    // no super
    Method();  // oops
  }
}
JaredPar
+1  A: 

Sometimes I use it to create parameters for a constructor of superclass. But the method has to be static:

class MyImplementation extends SuperImplementation {
   public MyImplementation(String input) {
      super(convertInput(input));
      ...
   }

   private static String convertInput (String input) {
      String output = "";
      // do something with input and put it to output
      return output;
   }
 }
Andreas_D
+3  A: 

I don't see anyone answering your actual question yet...

private static String doSmth () {
    //what I can NOT do here?
}

You can do whatever you want there. The method is static, so you can access all the static fields you'd like. Your compiler will stop you from attempting to access instance-specific methods/fields.

Furthermore, nothing prevents you from using your static method in the constructor, or even as a prerequisite to a call to a super() constructor:

public Bar () {
    super (doSmth());
    /* ... */
 }

... as long as doSmth() is static, you're golden.

Dolph
+3  A: 

The simple rule is do not access, directly or indirectly, the "this" object from within a constructor.

That means you should not call overrideable methods from a constructor, nor should you call a method that calls an overrideable method, or call a method that calls a method that calls an overrideable method, or ... you get the idea.

It also means that you should not pass "this" to anything, as the other thing could call an overrideable method.

In your particular case what you have is fine. If it were to change to:

class Bar extends Foo 
{
    public Bar () {
        super (doSmth(this));
        ...
    }

    private static String doSmth (Bar bar) {
        //what I can NOT do here?
   }
}

Then you would have a (potential) problem because doSmth could call an overriden method in subclass of Bar that relies on data that hasn't been initialized yet.

Here is an example of what could happen:

public class Main
{
    public static void main(final String[] argv)
    {
        final A a;

        a = new B();
        a.foo();
    }
}

abstract class A
{
    protected A()
    {
        bar(this);
    }

    private static void bar(final A a)
    {
        a.foo();
    }

    public abstract void foo();
}

class B extends A
{
    final String str;

    public B()
    {
        super();
        str = "Hello, World!";
    }

    public void foo()
    {
        System.out.println("str - " + str);
    }
}

So, as long as you don't call any overridden methods you are good. However it is safest to just follow the "rule" of never passing this outside of the constructor and never invoking overrideable (non-final) methods, directly or indirectly from a constructor.

TofuBeer
Thanks, very clear.
Roman