简体   繁体   中英

Accessing constructor from abstract base class with reflection

I'm playing around with Java's Reflection. I have an abstract class Base with a constructor.

abstract class Base {
    public Base( String foo ) {
        // do some magic
    }
}

I have some further classes extending Base . They don't contain much logic. I want to instantiate them with Base 's constructor, without having to write some proxy contructors in those derived classes. And of course, I want to instantiate those derived classes with Reflection. Say:

Class cls = SomeDerivedClass.class;
Constructor constr;
constr = cls.getConstructor( new Class[] { String.class } ); // will return null
Class clsBase = Base.class;
constr = clsBase.getConstructor( new Class[] { String.class } ); // ok
Base obj = (Base) constr.newInstance( new Object[] { "foo" } ); // will throw InstantiationException because it belongs to an abstract class

Any ideas, how I can instantiate a derived class with Base's constructor? Or must I declare those dumb proxy constructors?

A class does not inherit constructors from it parent. A class does not have it parents constructors (though it can call them) So you have to call the constructors the class has, not a constructor a super class has.

The default constructor only appears to do this because it calls the default constructor of the parent by default. If the parent doesn't have a default constructor, neither can its immediate children.

我担心你的子类甚至不会编译,直到你有一个显式构造函数调用其中一个super()构造函数。

You cannot construct an abstract class without specifying all of the details that will make it "non-abstract".

That means in the example:

public abstract class Parent {
  String name;

  public Parent(String name) {
    this.name = name;
  }

  abstract public String getName();

}

no amount of constructor manipulating via reflection will return a Parent-only class. You can however, return an "anonymous" class by specifying the abstract details at construction time, like so:

Parent parent = new Parent() {
    public String getName() { return "Bob"; }
  };

Remember, sub-classing also calls the parent constructor, even if you don't put the code in explicitly. A sub-class written like:

public class Child extends Parent {
  public Child(String name) {
  }
}

will look for a no arg constructor in the Parent class. If it finds one, then it will be compiled into code equivalent to

public class Child extends Parent {
  public Child(String name) {
    super();
  }
}

If it doesn't find a no argument constructor in the Parent class, it will fail to compile until you explicitly specify the parent class construction with the super(name); constructor call.

Another thing to remember, all classes are subclasses of Object , so if you don't provide an extends SomeClass like so:

public class JustMe {
}

The compiler conceputally "corrects" you code at compile time to:

public class JustMe extends Object {

   public JustMe() {
     super();
   }
}

The Object class has a bunch of native (non-Java) code within it to register with the JVM ensuring correct garbage collection, memory management, type enforcement, etc. are followed over the life of the Object.

ie. You can't get around it, the JVM will stop you from constructing and abstract class unless all of it's methods can be resolved via anonymous classes or subclasses.

The problem is your base class constructor is nondefault (has a parameter). Thus it can't be called implicitly by a generated default subclass constructor. (In fact you should get a compilation warning/error about this.) I am afraid you need to add explicit subclass constructor(s).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM