Is there a way to make a method which is not abstract but must be overridden?

11,803

Solution 1

There is no direct compiler-enforced way to do this, as far as I know.

You could work around it by not making the parent class instantiable, but instead providing a factory method that creates an instance of some (possible private) subclass that has the default implementation:

public abstract class Base {
  public static Base create() {
    return new DefaultBase();
  }

  public abstract void frobnicate();

  static class DefaultBase extends Base {
    public void frobnicate() {
      // default frobnication implementation
    }
  }
}

You can't write new Base() now, but you can do Base.create() to get the default implementation.

Solution 2

As others have pointed out, you can't do this directly.

But one way to do this is to use the Strategy pattern, like so:

public class Base {
    private final Strategy impl;

    // Public factory method uses DefaultStrategy
    // You could also use a public constructor here, but then subclasses would
    // be able to use that public constructor instead of the protected one
    public static Base newInstance() {
        return new Base(new DefaultStrategy());
    }

    // Subclasses must provide a Strategy implementation
    protected Base(Strategy impl) {
        this.impl = impl;
    }

    // Method is final: subclasses can "override" by providing a different
    // implementation of the Strategy interface
    public final void foo() {
        impl.foo();
    }

    // A subclass must provide an object that implements this interface
    public interface Strategy {
        void foo();
    }

    // This implementation is private, so subclasses cannot access it
    // It could also be made protected if you prefer
    private static DefaultStrategy implements Strategy {
        @Override
        public void foo() {
            // Default foo() implementation goes here
        }
    }
}

Solution 3

Consider making an interface with this method. Class descendants will have to implement it.

Solution 4

I think the easiest way is to create an abstract class that inherits from the base class:


public class Base {
    public void foo() {
        // original method
    }
}

abstract class BaseToInheritFrom extends Base {
    @Override
    public abstract void foo();
}

class RealBaseImpl extends BaseToInheritFrom {
    @Override
    public void foo() {
        // real impl
    }
}

Solution 5

How about this: inside the default implementation of the method, use reflection to get the exact Class of the object. If the Class does not match your base class exactly, throw a RuntimeException or equivalent.

public class Parent {

    public void defaultImpl(){
        if(this.getClass() != Parent.class){
            throw new RuntimeException();
        }
    }

}
Share:
11,803
Admin
Author by

Admin

Updated on June 25, 2022

Comments

  • Admin
    Admin almost 2 years

    Is there any way of forcing child classes to override a non-abstract method of super class?

    I need to be able to create instances of parent class, but if a class extends this class, it must give its own definition of some methods.

  • Joachim Sauer
    Joachim Sauer over 12 years
    How would that help? If the base class needs to be instantiable, then it too would need to implement it. This would negate the need of the derived classes to implement them methods.
  • Joachim Sauer
    Joachim Sauer over 12 years
    It's a workaround that I've seen (in a similar way, at least) in SWT. It's a last resort, but a solution that would lead to a compilation error would certainly be better.
  • curioustechizen
    curioustechizen over 12 years
    Ah right.. I did not realize the OP was looking for a solution which would enforce this at compile time. And most certainly, a compilation error is any day better than a runtime exception. BTW, I have seen something similar in the Android APIs - they enforce that certain methods must call through to the super implementation, failing which a runtime exception is thrown.
  • Anthony
    Anthony over 12 years
    I feel the need to point out that a child class will not be able to get the parent's default implementation by calling super.frobincate() because a child class will be inheriting Base and not DefaultBase. Otherwise, this is a great work-around I think.
  • Ivan Nikitin
    Ivan Nikitin over 12 years
    There is no need to implement it by the base class. Ask for an interface instance where you need to use the derived object, not a base class instance. This will force derived classes to have an interface implementation. You may check for a base class type in the method body also.
  • KeithS
    KeithS over 12 years
    you can't "force" all child classes of the base class to implement an interface that the base class does not implement. And, if the base class didn't implement the interface, but had a named method that would satisfy the contract (meeting the LSP), then the interface on the derived class would be met by virtue of the existence of the base class's method.
  • Visionary Software Solutions
    Visionary Software Solutions over 12 years
    Nicely done. This is probably the most elegant way of dealing with this issue.
  • Dave
    Dave over 12 years
    This is the better way because it's bad design to override methods that have definitions. All methods should be final, abstract, or empty.
  • dfeuer
    dfeuer about 10 years
    The conceptual reason is this: there does exist an annotation indicating that an overriding method must call the overridden one. Combining those two annotations allows you to create a method that does some basic work that must be the same for all subclasses, but not enough, because you already know that's not going to be enough, and you want to be sure that the subclass remembers to finish the job.
  • user541686
    user541686 about 10 years
    @dfeuer: How could you possibly prevent a situation of the derived class "calling" the base class method like if (false) super.Foo();?
  • dfeuer
    dfeuer about 10 years
    the intention (or at least my intention when I went searching for this question) was not to make sure no one broke it on purpose, but to make sure no one broke it by mistake!
  • user541686
    user541686 about 10 years
    @dfeuer: Oh I see, interesting... I got the impression the question was really about enforcement. For preventing mistakes, I'm not sure, it might've been a nice feature. I guess in Java they wanted to keep it simple when it's not totally necessary?
  • Syed Aqeel Ashiq
    Syed Aqeel Ashiq almost 2 years
    Aah I want to mark this as accepted this answer, but my old SO account is lost :'(