使用反射从抽象基类访问构造函数

Posted

技术标签:

【中文标题】使用反射从抽象基类访问构造函数【英文标题】:Accessing constructor from abstract base class with reflection 【发布时间】:2011-01-13 16:46:31 【问题描述】:

我正在玩 Java 的反射。我有一个带有构造函数的抽象类Base

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

我还有一些扩展Base 的课程。它们不包含太多逻辑。我想用Base 的构造函数来实例化它们,而不必在这些派生类中编写一些代理构造函数。当然,我想用反射实例化那些派生类。说:

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

任何想法,我如何用 Base 的构造函数实例化派生类?或者必须我声明那些愚蠢的代理构造函数?

【问题讨论】:

在实例化这些类之前,你确定一切都在编译吗? 是的,它编译得很好。这是一个简化的示例,它缺少那些 catch 子句,但基本上这段代码编译得很好。啊,Base 有一个额外的空默认构造函数(javac 坚持这样做)。 【参考方案1】:

一个类不会从它的父类继承构造函数。一个类没有它的父构造函数(尽管它可以调用它们)所以你必须调用类的构造函数,而不是超类的构造函数。

默认构造函数似乎只执行此操作,因为它默认调用父级的默认构造函数。如果父级没有默认构造函数,则其直接子级也没有。

【讨论】:

【参考方案2】:

恐怕你的子类甚至不会编译,除非你有一个显式的构造函数调用 super() 构造函数之一。

【讨论】:

一切编译正常。 Base(String) 不会在任何子类中被调用。但是我必须为Base 定义一次空的默认构造函数。 这是一个至关重要的区别。这意味着您的子类将编译和实例化,但只会调用空的父构造函数。除非子类在其构造函数中显式调用它,否则您无法访问其他构造函数。【参考方案3】:

如果不指定使其“非抽象”的所有细节,您就无法构造抽象类。

例子中的意思是:

public abstract class Parent 
  String name;

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

  abstract public String getName();


任何通过反射操作的构造函数都不会返回仅父类。但是,您可以通过在构造时指定抽象详细信息来返回“匿名”类,如下所示:

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

请记住,子类化也会调用父构造函数,即使您没有显式地放入代码。一个子类写成这样:

public class Child extends Parent 
  public Child(String name) 
  

将在Parent 类中查找无参数构造函数。如果找到,则将其编译为等价于

的代码
public class Child extends Parent 
  public Child(String name) 
    super();
  

如果在 Parent 类中没有找到无参数构造函数,它将无法编译,直到您使用 super(name); 构造函数调用显式指定父类构造。

另外要记住的是,所有类都是Object 的子类,所以如果你不提供extends SomeClass 像这样:

public class JustMe 

编译器在编译时从概念上“纠正”您的代码:

public class JustMe extends Object 

   public JustMe() 
     super();
   

Object 类中有一堆本地(非 Java)代码,用于向 JVM 注册,以确保在 Object 的整个生命周期中都遵循正确的垃圾收集、内存管理、类型强制等。

即。你无法绕过它,JVM会阻止你构造和抽象类,除非它的所有方法都可以通过匿名类或子类解决。

【讨论】:

子类化除了无参数的父构造函数(如果存在的话)不会隐式调用任何东西。它绝对不会自行传递参数。此外,如果抽象类的构造函数需要参数,您也应该在创建匿名类时指定它,因此匿名示例应为: new Parent( "foo" ) ... @biziclop 感谢您的出色观察,为子孙后代而更正【参考方案4】:

问题是你的基类构造函数是非默认的(有一个参数)。因此它不能被生成的默认子类构造函数隐式调用。 (事实上​​你应该得到一个关于这个的编译警告/错误。)恐怕你需要添加显式的子类构造函数。

【讨论】:

我没有收到任何警告。可能是因为Base 和派生类位于不同的包中,位于不同的 Eclipse 项目中。

以上是关于使用反射从抽象基类访问构造函数的主要内容,如果未能解决你的问题,请参考以下文章

请问把基类构造函数声明为protected有啥好处呢(抽象基类)

C#在自己的构造函数之后调用基类的构造函数?

抽象类借口构造函数静态方法成员

访问从基类构造函数调用的重写方法中的私有方法

将参数传递给基类构造函数

无法从派生类构造函数参数访问受保护的基类成员[重复]