views:

226

answers:

12

If I have a class:

class A {
   public A() { }
}

and another

class B extends A {
   public B() { }
}

is there any way to get B.B() not to call A.A()?

A: 

No way. If you were to do it, the object might turn out to be in inconsistent state.

The compiler automatically adds super() in the beginning of each constructor.

Bozho
+1  A: 

No and if you could, your derived object wouldn't really be the object it's deriving from now would it? The is-a principle would be violated. So if you really need it, then polymorphism isn't what you're after.

Blindy
A: 

Every superclass needs to be constructed and there is no other way then calling a constructor.

Andreas_D
A: 

I think the only way to do it is messing up with the byte-code.
I'm not sure if the Classloader or the JVM checks if super() is being called, but, as Bozho wrote, you probably would end with inconsistent objects when doing so.

Carlos Heuberger
+6  A: 

There is absolutely no way to do this in Java; it would break the language specification.

JLS 12 Execution / 12.5 Creation of New Class Instances

Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

  1. Assign the arguments for the constructor [...]
  2. If this constructor begins with an explicit constructor invocation of another constructor in the same class (using this), then [...]
  3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super).
  4. Execute the instance initializers and instance variable initializers for this class [...]
  5. Execute the rest of the body of this constructor [...]
polygenelubricants
+6  A: 

If you don't want to call the superclass constructor, there is something else wrong with your object model.

Dolph
+2  A: 

The closest you can achieve to the desired behaviour is to delegate initialisation normally performed in the constructor to a template method, which you then override in your subclass implementation. For example:

public class A {
  private Writer writer;

  public A() {
    init();
  }

  protected void init() {
    writer = new FileWriter(new File("foo.txt"));
  }
}

public class B extends A {
  protected void init() {
    writer = new PaperbackWriter();
  }
}

However, as other people have noted this can typically indicate a problem with your design and I typically prefer the composition approach in this scenario; for example in the above code you could define the constructor to accept a Writer implementation as a parameter.

Adamski
"Effective Java 2nd Edition, Item 17: Design and document for inheritance, or else prohibit it: Constructors must not invoke overridable methods, directly or indirectly."
polygenelubricants
I'm not saying it's a good thing - I'm just saying that's how you'd go about doing it.
Adamski
A: 

Nope - you cannot do it and why would you want to do it anyway? That would mess up your object model.

Anyways - i believe if you still want to do it and then you would have to manipulate the generated byte code.... there are a couple of libraries available that make it easy to instrument the byte code.

Strongly suggest against doing it...

arcamax
A: 

Every object in java is a subclass of Object (object with a capital 'O'). when you create an object of a subclass the super class constructor is invoked. Even if your class is not inhereting anyother class, implicitly it is inheriting Object, so the Object constructor has to be called. So super() is invoked for this purpose.

srikanth
A: 

Assuming you mean

class B extends A {
     public B() { }
}

then sure you can

class B extends A {
     public B() {
         this(abort());
     }
     private B(Void dummy) {
         /* super(); */
     }
     private static Void abort() {
         throw null;
     }
}

Not very useful. The interface [not Java keyword] to class A says that you need to run its constructor in order to construct it, not unreasonably. The exception is that serialisable classes are constructed without calling the constructors of the serialisable classes.

Tom Hawtin - tackline
A: 
  1. As pointed out by another poster, B doesn't extend A, so it won't call A's constructor anyways.

  2. There is no way to do this in Java.

  3. You can probably accomplish equivalently what you want to do as follows:

a) in each class of your hierarchy, include a constructor with a unique signature that calls the superclass's constructor with its arguments. For example, declare a class "Noop" and a constructor that takes that as an argument:

public class NoOp {
}

public class class1 {
    class1() {
        System.out.println("class1() called");
    }
    class1(String x, String y) {
        System.out.println("class1(String, String) called");
}
    class1(NoOp x) {
        System.out.println("class1(NoOp) called");
    }
}

public class class2 extends class1 {
    class2() {
        System.out.println("class2() called");
    }
    class2(String x, String y) {
        System.out.println("class2(String, String) called");
}
    class2(NoOp x) {
        super(x);
        System.out.println("class2(NoOp) called");
    }
}

public class class3 extends class2 {
    class3() {
        System.out.println("class3() called");
    }
    class3(String x, String y) {
        super(new NoOp());
        System.out.println("class3(String, String) called");
    }
    class3(NoOp x) {
        super(x);
        System.out.println("class3(NoOp) called");
    }
    public static void main(String args[]) {
        class3 x = new class3("hello", "world");
    }
}

If you run this you will get the output

class1(NoOp) called
class2(NoOp) called
class3(String, String) called

So, effectively you have created a class3 constructor that only calls constructors that don't do anything.

Larry Watanabe
A: 

Thank you so much. All the suggestions are quite helpful.

Unfortunately I am trying to superclass an existing package. I ended up side-stepping the problem by writing my own class (which is almost exactly the same as that provided by the package): http://stackoverflow.com/questions/2962491/any-way-to-turn-off-quips-in-ooweb

Thank you! Misha

Misha Koshelev
You can avoid calling the constructor with Unsafe.allocateInstance(Class) in Sun's JVM. This will avoid B() and A(). You can have a method which does whatever you need B() to do (or use reflection to do it) NOTE: Handle with care.
Peter Lawrey