it-roy-ru.com

Конструкторы по умолчанию в Java

Я знаю, что задаю здесь серьезный вопрос ...

У меня есть некоторый класс Foo и класс Bar, который расширяет Foo. В Foo у меня есть конструктор, который принимает набор параметров, которые он устанавливает в своих полях. Производные классы, такие как Bar, обычно не нуждаются в изменении этого. Теперь мой IDE дает мне «В Foo нет конструктора по умолчанию» . Из небольшого количества Google это выглядит потому, что «конструкторы не наследуются». Итак, все хорошо, но как мне теперь заставить это работать, не дублируя этот конструктор в каждом производном классе? Я предполагаю, что есть более вменяемый подход?

50
Jeroen De Dauw

Используйте конструктор super:

public Bar(int a, double b, ...) {
    super(a, b, ...);
}
61
arshajii

Итак, все хорошо, но как мне теперь заставить это работать, не дублируя этот конструктор в каждом производном классе?

Вам нужно продублировать конструктор подписи - если вы хотите, чтобы у подкласса были конструкторы с одинаковыми сигнатурами. Но вам не нужно дублировать code - вы просто добавляете цепочку к конструктору суперкласса:

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
}

Вам действительно нужно выяснить, какая информация требуется для создания Bar -, что должно диктовать ваши конструкторы.

Если это проблема, возможно, вы злоупотребляете наследованием. Трудно сказать наверняка, не имея представления о том, каковы ваши фактические классы, но вы должны обратить внимание на использование композиции вместо наследования. Это не панацея, но она может избежать такого рода вещей.

16
Jon Skeet

Проблема решается с помощью этого:

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 () "(всегда должен быть один, если не указано явно).

3
Gaston Flores

Нет, больше нет "нормального" подхода. Если ваш базовый класс не имеет конструктора по умолчанию, вы должны явно вызвать правильный конструктор из всех дочерних классов.

Обратите внимание, это не означает, что дочерние классы должны иметь точный тот же конструктор, что и базовый класс. Например, это совершенно верно:

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);
    }
}
3
m0skit0

Эта ошибка также может произойти, потому что вы вызываете свой супер-конструктор последним. Возможно, вам придется переместить это, чтобы быть первым утверждением:

    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;
    }
0
live-love

JVM не предоставит конструктор по умолчанию, если вы его предоставили по причинам проектирования. Что вы можете сделать, определить конструктор в Bar с той же сигнатурой и вызвать super ().

public Bar(int x,int y) {
    super(x,y);
}
0
Aniket Thakur

Если параметры не требуются и/или имеют значения по умолчанию, вы можете определить конструктор по умолчанию (без параметров):

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;

}
0
Vasilii Suricov