-1

I was asked this question in a recent interview. Looking to get some help.

  • Class A has foo() method triggered from constructor.
public class A {

    public A() {
        foo();
    }

    public void foo() {
        System.out.println("In foo method in class A");
    }
}

Class B overrides the foo method in class A.

public class B extends A {

    @Override
    public void foo() {
        System.out.println("In foo method in class B");
    }
}

Now if we create instance of class B the foo() method in B will be called.

A a = new B();
prints: "In foo method in class B"

Question: Lets say we own the class A and it is part of a jar file(abc.jar) and how do we make sure when class B is instantiated A.foo() is called instead of overridden B.foo()?

Conditions:

  1. Imagine the jar is shared to other users and we cannot break client code my marking the method private/final.

  2. Also calling super.foo() from class B is also not an option since we don't own class B and cannot restrict users.

sat
  • 3
  • 2
  • Related: [What's wrong with overridable method calls in constructors?](https://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors) – John Kugelman Nov 18 '20 at 16:28
  • Welcome to SO! It would be helpful if you added what you tried and attempted to help answerers. – abhivemp Nov 18 '20 at 16:38

2 Answers2

2
public class A {

    public A() {
        fooInternal();
    }

    public void foo() {
        fooInternal();
    }

    private final void fooInternal() {
        System.out.println("In foo method in class A");
    }
}

You can't make it invoke A.foo(), because that method is overridden. You can only make it invoke a method that A.foo() invokes, and that can't be overridden.

The more important point here is that you shouldn't ever invoke overrideable methods from a constructor.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
1

Mark A's foo method as final. It is the only way.

In order to still allow B to also get a ping on initialization, the solution is a two-stage construct: A's constructor invokes the final foo() method, but as part of the foo() method, foo2, or subfoo, or whatever you want to call it, is also invoked, and that method is defined in A as a noop (does nothing).

Generally such a final init()-style method should also be private. Based on common logic: What are the odds that an 'init' operation is also a concept that external code could plausibly want to invoke a second time at some arbitrary later point in time? Highly unlikely, which is why it should be private. Once you do so, well, private methods are effectively inherently final, so that takes care of that:

class A {
    public A() {
        init0();
    }

    private final init0() {
        // do stuff here - subclasses won't stop you.
        init();
    }

    // B can override this if it wants.
    protected void init() {}
}
rzwitserloot
  • 85,357
  • 5
  • 51
  • 72