61

我知道我在这里问了一些严肃的 101 问题......

我有一些类Foo和一个Bar扩展类Foo。在Foo我有一个构造函数,它接受一组参数,并将其设置为它的字段。派生类例如Bar通常不需要修改它。现在我的 IDE 给了我"There is no default constructor available in Foo"。从一些谷歌搜索来看,这似乎是因为“构造函数不是继承的”。一切都很好,但是我现在如何在不在每个派生类中复制这个构造函数的情况下让它工作呢?我假设有一个更理智的方法?

4

7 回答 7

77

使用super构造函数:

public Bar(int a, double b, ...) {
    super(a, b, ...);
}
于 2013-06-12T14:43:23.257 回答
22

一切都很好,但是我现在如何在不在每个派生类中复制这个构造函数的情况下让它工作呢?

您确实需要复制构造函数签名- 如果您希望子类具有具有相同签名的构造函数。但是您不需要复制代码- 您只需链接到超类构造函数:

public Bar(int x, int y) {
    super(x, y);
    // Any subclass-specific code
}

当然,如果您可以从一组不同的参数中计算出超类参数,那很好。例如:

public Bar(int x) {
    super(x, x * 2);
    // Any subclass-specific code
}

您确实需要弄清楚构建 a 所需的信息Bar-应该决定您的构造函数。

如果这是一个问题,则可能是您过度使用了继承。如果不知道您的实际类是什么,很难确定,但您应该考虑使用组合而不是继承。它不是灵丹妙药,但它可以避免这种事情。

于 2013-06-12T14:44:53.843 回答
5

不,没有更多的“理智”方法。如果您的基类没有默认构造函数,那么您必须从所有子类中显式调用正确的构造函数。

请注意,这并不意味着子类需要具有与基类完全相同的构造函数。例如,这是完全有效的:

class Foo {

    protected int a;
    protected int b;

    protected Foo(final int a, final int b) {
        this.a = a;
        this.b = b;
    }
}

class Bar extends Foo {

    protected Bar() {
        super(0,0);
    }
}
于 2013-06-12T14:43:34.307 回答
3

问题是这样解决的:

class Foo{
       Foo(int a, int b){}
}

class Bar extends Foo{
         //Here must be a constructor OR declare a constructor in Foo without parameters
         Bar(){super(1,1)} //this is an example

}

其他解决方案是:

class Foo{
   Foo(int a, int b){}
   Foo(){}
}

class Bar extends Foo{
}

请记住,如果在SuperClass中有一个带参数的构造函数(在本例中为 Foo),则子类(在本例中为 Bar)上的隐式构造函数总是会隐式调用“ Super() ”(总是必须是一个除非明确)。

于 2013-06-12T14:49:13.317 回答
1

此错误也可能发生,因为您最后调用了超级构造函数。您可能必须将其移动为第一个语句:

    public SectionsPagerAdapter(FragmentManager manager, List<Fragment> fragmentList) {
        mFragmentList  = fragmentList;
        super(manager);

    }

    public SectionsPagerAdapter(FragmentManager manager, List<Fragment> fragmentList) {
        super(manager); --> this should come first
        mFragmentList  = fragmentList;
    }
于 2018-11-28T17:02:07.300 回答
0

如果您出于设计原因提供了默认构造函数,JVM 将不会提供默认构造函数。您可以做什么在 Bar 中定义具有相同签名的构造函数并调用 super()。

public Bar(int x,int y) {
    super(x,y);
}
于 2013-06-12T14:47:45.833 回答
0

如果不需要参数和/或具有默认值,那么您可以定义默认构造函数(不带参数):

class Foo
{
    public final int DEFAULT_A = 42;
    protected int a;
    protected int b;

    public Foo(final int a, final int b)
    {
        this.a = a;
        this.b = b;
    }

    // Is equal to new Foo(Foo.DEFAULT_A, 0);
    public Foo()
    {
        this.a = this.DEFAULT_A;
    }

}

class Bar extends Foo {}

class PiBar extends Bar
{
    public final int DEFAULT_A = Math.PI;

}
于 2017-12-13T15:41:25.520 回答