Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create instance of subclass with constructor from super class

Tags:

java

I'd like to create a registry for classes which are subclasses of a super class. The classes are stored in a map which acts as registry. A class is picked from the registry depending on a key and an instance of that class will be created via reflection.

I'd like to instantiate a class depending on a constructor (with 1 parameter) of the super class. It works only if I declare the constructor in the subclasses as well.

Is there a way to instantiate the class using a constructor of a super class? Is there a way to make that code type-safe?

Example code:

public class ReflectionTest {

    /**
     * Base class with no-args constructor and another constructor with 1 parameter
     */
    public static class BaseClass {

        Object object;

        public BaseClass() {
            System.out.println("Constructor with no args");
        }

        public BaseClass( Object object) {
            this.object = object;
            System.out.println("Constructor with parameter= " + object);
        }

        public String toString() {
            return "Object = " + object;
        }
    }

    /**
     * Subclass with 1 parameter constructor
     */
    public static class SubClass1 extends BaseClass {
        public SubClass1( Object object) {
            super(object);
        }
    }

    /**
     * Subclass with no-args constructor
     */
    public static class SubClass2 extends BaseClass {

    }

    public static void main(String[] args) {

        // registry for classes
        Map<Integer,Class<?>> registry = new HashMap<>();
        registry.put(0, SubClass1.class);
        registry.put(1, SubClass2.class);

        // iterate through classes and create instances
        for( Integer key: registry.keySet()) {

            // get class from registry
            Class<?> clazz = registry.get(key);

            try {

                // get constructor with parameter
                Constructor constructor = clazz.getDeclaredConstructor( Object.class);

                // instantiate class
                BaseClass instance = (BaseClass) constructor.newInstance(key);

                // logging
                System.out.println("Instance for key " + key + ", " + instance);

            } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                e.printStackTrace();
            }

        }

        System.exit(0);
    }
}

The example gives the following console output:

Constructor with parameter= 0
Instance for key 0, Object = 0
java.lang.NoSuchMethodException: swing.table.ReflectionTest$SubClass2.<init>(java.lang.Object)
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getConstructor(Class.java:1825)
    at swing.table.ReflectionTest.main(ReflectionTest.java:63)
like image 418
Roland Avatar asked Mar 09 '16 06:03

Roland


People also ask

How do you call a super class constructor in a subclass?

To explicitly call the superclass constructor from the subclass constructor, we use super() . It's a special form of the super keyword. super() can be used only inside the subclass constructor and must be the first statement.

Can you call a sub class constructor from super class constructor?

No, we cannot call subclass constructor from superclass constructor.

When you create an object of a subclass the constructor of the superclass calls the constructor of the subclass True or false?

(*2) A subclass constructor always calls the constructor of its superclass, and so on up to the Object constructor, to initialize all the aspects of the instance that the subclass inherits from its superclass.

How do you call a super class constructor when initializing a subclass instance?

Use __init()__ on super() inside the constructor of the subclass to invoke the constructor of the superclass in Python. In inheritance invoking the super constructor of a subclass invokes the constructor of its superclass.


2 Answers

  1. A superclass has no knowledge of its children.
  2. Constructors are not inherited.

Therefore, without making assumptions about the subclass ctor, you cannot write the code that you want.

So what can you do? Use an Abstract Factory pattern.

We can create an interface Factory:

@FunctionalInterface
public interface SuperclassFactory {
    Superclass newInstance(Object o);
}

You could create more than one method on the Factory, but that would make it less neat for lambdas.

Now you have a Map<Integer, SuperclassFactory>, and populate it:

Map<Integer,SuperclassFactory> registry = new HashMap<>();
registry.put(0, SubClass1::new);
registry.put(1, SubClass2::new);

So, in order to use this Map you simply do:

for(final Map.Entry<Integer,SuperclassFactory> e: registry.entrySet()) {
    //...
    final BaseClass instance = e.getValue().newInstance(e.getKey());
    //...
}

If your subclass does not have the appropriate ctor, this code will not compile as there will be no ctor reference that can be used. This is Good Thing (TM). In order to compile with the current Subclass2 you would need to use:

registry.put(1, obj -> new SubClass2());

So now we have:

  1. Lost the reflection
  2. Acquired compile time type safety
  3. Lost the ugly cast (although that was through misuse of reflection)

N.B. loop through a Map's entrySet() not its keySet().

like image 54
Boris the Spider Avatar answered Sep 28 '22 17:09

Boris the Spider


Constructors need to be defined explicitly in the subclass. If a constructor is defined in superclass that doesn't mean that constructor can be used to create an instance of subclass whether you are using reflection or not.

Since your SubClass2 doesn't have constructor with one argument, so when you try to create an instance of it with one argument, it's throwing NoSuchMethodException.

like image 38
Ankit Bansal Avatar answered Sep 28 '22 18:09

Ankit Bansal