it-roy-ru.com

Ошибка Java: неявный супер-конструктор не определен для конструктора по умолчанию

У меня есть простой Java-код, который выглядит примерно так:

abstract public class BaseClass {
    String someString;
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public ASubClass(String someString) {
        super(someString);
    }
    public String getName() {
        return "name value for ASubClass";
    }
}

У меня будет довольно много подклассов BaseClass, каждый из которых реализует метод getName() по-своему ( шаблон метода шаблона ).

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

Когда я удаляю конструктор из подклассов, я получаю эту ошибку во время компиляции:

Implicit super constructor BaseClass() is undefined for default constructor. Must define an explicit constructor

Возможно ли то, что я пытаюсь сделать?

85
Joel

Вы получаете эту ошибку, потому что класс, у которого нет конструктора, имеет default constructor, который не имеет аргументов и эквивалентен следующему коду:

public ACSubClass() {
    super();
}

Однако, так как ваш BaseClass объявляет конструктор (и, следовательно, не имеет конструктора по умолчанию, конструктора без аргументов, который компилятор мог бы обеспечить в противном случае), это недопустимо - класс, расширяющий BaseClass, не может вызвать super();, потому что нет аргумента no конструктор в BaseClass.

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

Самый простой способ обойти это - для базового класса не объявлять конструктор (и, следовательно, иметь конструктор по умолчанию, без аргументов) или иметь объявленный конструктор без аргументов (сам по себе или вместе с любыми другими конструкторами). Но часто этот подход не может быть применен - ​​потому что вам нужны любые аргументы, передаваемые в конструктор, чтобы создать допустимый экземпляр класса.

140
matt b

Для тех, кто Google для этой ошибки и приехать сюда: может быть другая причина для ее получения. Eclipse выдает эту ошибку при настройке проекта - несоответствие конфигурации системы.

Например, если вы импортируете проект Java 1.7 в Eclipse, и у вас неправильно настроен 1.7, вы получите эту ошибку. Затем вы можете перейти к Project - Preference - Java - Compiler и switch to 1.6 or earlier; или перейдите к Window - Preferences - Java - Installed JREs и добавьте/исправьте установку JRE 1.7.

43
MF.OX

Это возможно, но не так, как у вас есть.

Вы должны добавить конструктор без аргументов в базовый класс и все!

public abstract class A {
    private String name;
    public A(){
        this.name = getName();
    }
    public abstract String getName();


    public String toString(){
        return "simple class name: " + this.getClass().getSimpleName() + " name:\"" + this.name + "\"";
    }
}
class B extends A {
    public String getName(){
        return "my name is B";
    }
    public static void main( String [] args ) {
        System.out.println( new C() );
    }
}
class C extends A {
    public String getName() {
        return "Zee";
    }
}

Когда вы не добавляете конструктор (любой) в класс, компилятор добавляет для вас конструктор по умолчанию без аргументов.

Когда значение по умолчанию no arg вызывает super (); и так как у вас его нет в суперклассе, вы получите это сообщение об ошибке.

Это вопрос сам по себе. 

Теперь расширяем ответ:

Знаете ли вы, что создание подкласса (поведения) для указания другого значения (данных) не имеет смысла ?? !!! Я надеюсь, что вы делаете.

Если единственное, что меняется, это «имя», то достаточно параметризовать один класс!

Таким образом, вам не нужно это:

MyClass a = new A("A");
MyClass b = new B("B");
MyClass c = new C("C");
MyClass d = new D("D");

или же 

MyClass a = new A(); // internally setting "A" "B", "C" etc.
MyClass b = new B();
MyClass c = new C();
MyClass d = new D();

Когда вы можете написать это:

MyClass a = new MyClass("A");
MyClass b = new MyClass("B");
MyClass c = new MyClass("C");
MyClass d = new MyClass("D");

Если бы я изменил сигнатуру метода конструктора BaseClass, мне пришлось бы изменить все подклассы.

Вот почему наследование - это артефакт, который создает HIGH-связывание, что нежелательно в OO системах. Этого следует избегать и, возможно, заменить композицией.

Подумайте, действительно ли они вам нужны как подкласс. Вот почему вы видите очень часто используемые интерфейсы:

 public interface NameAware {
     public String getName();
 }



 class A implements NameAware ...
 class B implements NameAware ...
 class C ... etc. 

Здесь B и C могли бы унаследовать от A, что могло бы создать очень ВЫСОКУЮ связь между ними, используя интерфейсы, связь уменьшается, если A решит, что больше не будет «NameAware», другие классы не сломаются.

Конечно, если вы хотите повторно использовать поведение, это не сработает. 

7
OscarRyz

Вы также можете получить эту ошибку, если JRE не установлен. Если это так, попробуйте добавить Системная библиотека JRE в ваш проект.

Под Eclipse IDE:

  1. откройте меню Project -> Свойства или щелкните правой кнопкой мыши свой проект в Package Explorer и выберите Свойства (Alt + Enter в Windows, Command + I на Mac)
  2. нажмите на Путь сборки Java затем Библиотеки вкладка
  3. выберите Modulepath или Classpath и нажмите Добавить библиотеку ... кнопка
  4. выберите Системная библиотека JRE затем нажмите Далее
  5. оставьте JRE рабочей области по умолчанию выбрано (вы также можете выбрать другой вариант) и нажмите Готово
  6. наконец нажмите Применить и закрыть .
1
yogesh kumar

Eclipse выдаст эту ошибку, если у вас нет вызова конструктора суперкласса в качестве первого оператора в конструкторе подкласса.

0
Sagar

ваш BaseClass нуждается в некоторой строке, поэтому доставить один.
Попробуй это: 

abstract public class BaseClass {
    String someString;
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public ASubClass() {
        super("someString");  // or a meaningfull value, same as getName()?
    }
    public String getName() {
        return "name value for ASubClass";
    }
}

или же 

abstract public class BaseClass {
    String someString;
    protected BaseClass() {  // for subclasses
        this.someString = null;  // or a meaningfull value
    }
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public String getName() {
        return "name value for ASubClass";
    }
}
0
Carlos Heuberger

Другой способ - вызвать super () с обязательным аргументом в качестве первого оператора в конструкторе производного класса.

public class Sup {
    public Sup(String s) { ...}
}

public class Sub extends Sup {
    public Sub() { super("hello"); .. }
}
0
user2407102

Извините за некропост, но столкнулся с этой проблемой только сегодня. Для всех, кто также сталкивается с этой проблемой - одной из возможных причин - вы не вызываете super в первой строке метода. Вторая, третья и другие строки запускают эту ошибку. Вызов super должен быть самым первым вызовом в вашем методе. В этом случае все хорошо.

0
Serj.by