Let's say I have a class, which implements a method (addThings()). It serves as a foundation of a tree of subclasses:
ParentClass {
protected void addThings() {
map.add(thing1);
map.add(thing2);
}
}
Now, let's say we implement a child class (which has Thing 3 as well) and Thing 3 also needs to be added on top of Thing 1 and Thing 2.
The obvious Java solution seems to be to have the child's class's implementation of the method call the super's method:
ChildClass extends ParentClass {
protected void addThings() {
super.addThings();
map.add(thing3);
}
}
The problem is that whoever implements the subclass may very well forget to do that, and have a bug:
ChildClassBad extends ParentClass {
protected void addThings() {
// BUG!!! Forgot to call super.addThings(); !!!
map.add(thing3);
}
}
Is there a way in Java to force any of the extending child (and grandchild) classes to always call a parent's method if they override it? (similar to how making a method abstract always forces them to implement it).
Please note that I need the solution to be propagatable down the inheritance tree.
In other words, if someone implements GrandChildClass which needs to add Thing4, they would suffer from the same bug possibility relative to ChildClass.
This means that the simple fix (applicable when you only have 1 level of inheritance) of having separate "addParentThings()" in ParentClass and then calling both addParentThings() and child-overridable empty addThings() is insufficient (because the grandchild has to override non-empty addThings).
A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass. A nested class has access to all the private members of its enclosing class—both fields and methods.
Super keyword in Method Overriding. The super keyword is used for calling the parent class method/constructor.
When an overridden method is called from within a subclass, it will always refer to the version of that method defined by the subclass. The version of the method defined by the superclass will be hidden.
It is what overriding for. The overridden method shall not be accessible from outside of the classes at all. But you can call it within the child class itself. to call a super class method from within a sub class you can use the super keyword.
Maybe try having a final method that calls another overridable method?
class ParentClass {
public final void doStuff() {
// Do stuff
onPostDoStuff();
}
protected void onPostDoStuff() {
// Override this!
}
}
And then in the child class:
class ChildClass extends ParentClass {
@Override
protected void onPostDoStuff() {
// Do extra stuff
}
}
You could even make the onPostDoStuff()
method abstract, so children have to override it.
If you are willing to make your doStuff
-Methods static for each class, which extends your ParentClass
and give your ParentClass
a final public void doAllStuff()
-Method, you can solve the problem with Reflection:
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Main
{
public static void main(String[] args) throws InterruptedException
{
A a = new C();
a.doAllStuff();
}
}
class A
{
protected List<String> list = new ArrayList<String>();
@SuppressWarnings("unused")
private static void doStuff(A a)
{
a.list.add("I am A");
}
final public void doAllStuff()
{
List<Class<?>> list = new ArrayList<Class<?>>();
Class<?> clazz = this.getClass();
while (A.class.getSuperclass() != clazz)
{
list.add(clazz);
clazz = clazz.getSuperclass();
}
System.out.println(list);
for (Class<?> myClass : list)
{
try
{
Method method = myClass.getDeclaredMethod("doStuff"
, myClass);
// Method is private? Make it accessible anyway.
method.setAccessible(true);
method.invoke(this, this);
}
catch (NoSuchMethodException e)
{
// Method not found, continue with next class.
continue;
}
catch (Exception e)
{
e.printStackTrace();
}
}
System.out.println(this.list);
}
}
class B extends A
{
@SuppressWarnings("unused")
private static void doStuff(B b)
{
b.list.add("I am B");
}
}
class C extends B {}
If you need to only call attributes, you can use getDeclaredField
, the fields may not be static
in this case.
The following approach enforces invocation of the superclass' setup method. The downside, or likely bug in subclasses, is that implementers might forget to provide a suitable constructor for providing an extension to the setup method. This means that child couldn't be extended by a grandchild.
Its also ugly because subclasses can't put subclass-specific setup in their extensions; they have to accept Parent
as a parameter.
Overall, the awkwardness difficulties here suggest that enforcement is better done, if at all, in a static analyzer, rather than javac
.
public class Parent
{
private final Consumer<Parent> setup;
protected final Collection<Object> x = new ArrayList<>();
public Parent()
{
setup = Parent::setupImpl;
}
protected Parent(Consumer<Parent> extension)
{
setup = ((Consumer<Parent>) Parent::setupImpl).andThen(extension);
}
public final void setup()
{
setup.accept(this);
}
private static void setupImpl(Parent it)
{
it.x.add("thing1");
it.x.add("thing2");
}
}
public class Child
extends Parent
{
public Child()
{
super(Child::setupImpl);
}
protected Child(Consumer<Parent> extension)
{
super(((Consumer<Parent>) Child::setupImpl).andThen(extension));
}
private static void setupImpl(Parent it)
{
it.x.add("thing3");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With