2011-01-13 87 views
6

我正在玩Java的Reflection。我有一个带构造函数的抽象类Base使用反射从抽象基类访问构造函数

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

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

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 

任何想法,我怎么能实例化与基的构造函数的派生类?或必须我声明那些愚蠢的代理构造函数?

+0

在实例化这些类之前,你确定一切都在编译? – gabuzo 2011-01-13 16:54:34

+0

是的,它编译得很好。这是一个简化的例子,它缺少这些catch-clause,但基本上这些代码编译得很好。啊,`Base`有一个额外的空默认构造函数(javac坚持)。 – craesh 2011-01-13 17:04:29

回答

9

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

默认的构造函数只会出现这样做,因为它默认调用父项的默认构造函数。如果父项没有默认的构造函数,它的直接子项也不会。

1

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

+0

我没有得到任何警告。也许是因为`Base`和派生类位于不同的包中,位于不同的Eclipse项目中。 – craesh 2011-01-13 16:57:34

2

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

+0

一切都很好。 `Base(String)`不会在任何子类中被调用。但是我必须为`Base`定义一个空的默认构造函数。 – craesh 2011-01-13 17:01:46

+0

虽然这是一个关键的区别。这意味着你的子类将编译和实例化,但只会调用空的父构造函数。除非子类在构造函数中显式调用它,否则无法访问其他构造函数。 – biziclop 2011-01-13 19:51:50

2

如果不指定所有使其成为“非抽象”的细节,则不能构造抽象类。

这意味着在例如:

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 { 
} 

编译器conceputally“纠正”您的代码在编译时:

public class JustMe extends Object { 

    public JustMe() { 
    super(); 
    } 
} 

Object类中有一堆本机(非Java)代码,用于在JVM中注册,以确保在Object的生命周期内遵循正确的垃圾回收,内存管理,类型执行等。

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