Помилка Java: неявний суперконструктор не визначений для конструктора за замовчуванням


89

У мене є якийсь простий код 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

Чи можливо те, що я намагаюся зробити?


1
Залиште конструктор "зайвий"! Він підтримує читабельність вашого коду, і всі сучасні середовища розробки можуть створювати його автоматично, тому вам просто потрібно натиснути ярлик.
Andreas Dolk,

3
Перечитавши власне запитання через рік, мені здається, що я міг видалити конструктори (включно з базовим класом), як запропонував matt b, а потім використовувати статичний заводський метод для побудови екземплярів.
Джоел

Відповіді:


146

Ви отримуєте цю помилку, оскільки клас, який не має конструктора, має конструктор за замовчуванням , який не має аргументів і еквівалентний наступному коду:

public ACSubClass() {
    super();
}

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

Це, мабуть, трохи протиінтуїтивно, оскільки ви можете подумати, що підклас автоматично має будь-який конструктор, який має базовий клас.

Найпростіший спосіб обійти це базовий клас не оголошувати конструктор (і, отже, мати конструктор за замовчуванням, no-arg) або мати оголошений конструктор no-arg (або сам по собі, або поряд з будь-якими іншими конструкторами). Але часто такий підхід не може бути застосований - тому що для побудови законного екземпляра класу вам потрібні будь-які аргументи, що передаються в конструктор.


17
"Це, мабуть, трохи протилежне інтуїції, оскільки ви можете подумати, що підклас автоматично має будь-який конструктор, який має базовий клас." +1
Mr_and_Mrs_D

2
Заради нащадків я запропоную своє рішення для майбутніх читачів: створіть конструктор no-arg, BaseClassале зробіть його просто кинути UnsupportedOperationExceptionабо щось інше. Це не найкраще рішення (воно хибно припускає, що клас може підтримувати конструктор no-arg), але це найкраще, що я можу придумати.
JMTyler

49

Для тих, хто шукає цю помилку в 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.


2
Щойно отримав цю помилку без видимої причини в Eclipse. Потім я очистив робочу область (меню Проект -> Очистити ...), і вона пішла.
erickrf

7

Це можливо, але не так, як у вас.

Вам потрібно додати конструктор no-args до базового класу і все!

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 для вас.

Коли defualt 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, мені довелося б змінити всі підкласи.

Ну ось чому успадкування - це артефакт, що створює ВИСОКЕ зчеплення, що небажано в системах ОО. Його слід уникати і, можливо, замінити композицією.

Подумайте, чи вони вам справді потрібні як підклас. Ось чому ви бачите дуже часто використовувані інтерфейси insted:

 public interface NameAware {
     public String getName();
 }



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

Тут B і C могли успадкувати від A, який створив би дуже ВИСОКУ зв'язок між ними, за допомогою інтерфейсів зв'язок зменшився, якщо A вирішив, що вона більше не буде "NameAware", інші класи не зламаються.

Звичайно, якщо ви хочете повторно використовувати поведінку, це не спрацює.


2
Так, за винятком того, що ви більше не можете переконатися, що ваші екземпляри ініціалізовані належним чином (наприклад, мають імена в цьому конкретному випадку)
ChssPly76

@ ChssPly76: Так, але це, мабуть, тому, що спадщина використовується погано. Я розширив свою відповідь, щоб висвітлити її.
OscarRyz

4

Ви також можете отримати цю помилку, коли JRE не встановлено. Якщо так, спробуйте додати системну бібліотеку JRE до свого проекту.

У розділі Eclipse IDE:

  1. відкрийте меню Проект -> Властивості , або клацніть правою кнопкою миші на своєму проекті в Провіднику пакетів і виберіть Властивості (Alt + Enter у Windows, Command + I на Mac)
  2. натисніть шлях побудови Java, а потім вкладку Бібліотеки
  3. вибрати Modulepath або Classpath і натисніть Додати бібліотеку ... кнопку
  4. виберіть системну бібліотеку JRE, а потім натисніть кнопку Далі
  5. тримати вибраним JRE робочої області за замовчуванням (ви також можете взяти інший варіант) і натисніть кнопку Готово
  6. нарешті натисніть Застосувати та Закрити .

2

Інший спосіб - виклик super () із необхідним аргументом як першим оператором у конструкторі похідного класу.

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

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

0

Eclipse дасть цю помилку, якщо у вас немає виклику конструктора супер класу як першого оператора в конструкторі підкласу.


0

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


0

Я вирішив вищезазначену проблему наступним чином:

  1. Клацніть на Проект.
  2. клацніть на властивості> Шлях побудови Java> Бібліотека> Системна бібліотека JRE> Редагувати
  3. Виберіть систему JRE And Finish за замовчуванням
  4. Застосувати і закрити.

-1

Ви можете вирішити цю помилку, додавши конструктор без аргументів до базового класу (як показано нижче).

На ура

 abstract public class BaseClass {
        // ADD AN ARGUMENTLESS CONSTRUCTOR TO THE BASE CLASS
        public 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";
    }
}

Це полегшує побудову невірно встановлених об’єктів (тих, що не мають someString) і, отже, повністю перешкоджає призначенню конструктора.
Роберт

-1

У мене була ця помилка та виправлена, видаливши викинуте виняток з поряд із методом до блоку try / catch

Наприклад: FROM:

public static HashMap<String, String> getMap() throws SQLException
{

}

ДО:

public static Hashmap<String,String> getMap()
{
  try{

  }catch(SQLException)
  { 
  }
}

Ця відповідь не має нічого спільного з помилками компілятора для відсутнього конструктора.
Роберт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.