2009-07-29 6 views
84

У меня есть простой код 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() метод по-своему (template method pattern).

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

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

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

Это то, что я пытаюсь сделать это возможно?

+1

Пожалуйста, оставьте «избыточный» конструктор! Он поддерживает читаемость вашего кода, и все современные IDE могут создавать его автоматически, поэтому вам просто нужно назначить ярлык. –

+3

Повторный просмотр моего собственного вопроса через год, и мне приходит в голову, что я мог бы удалить конструкторы (включая базовый класс), например матовый b, а затем использовать статический заводский метод для сборки экземпляров. – Joel

ответ

138

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

public ACSubClass() { 
    super(); 
} 

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

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

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

+16

«Это, вероятно, немного противоречит интуиции, потому что вы можете подумать, что подкласс автоматически имеет любой конструктор, который имеет базовый класс». +1 –

+1

Для потомков я предлагаю свое решение для будущих читателей: создайте конструктор no-arg в 'BaseClass', но просто попробуйте« UnsupportedOperationException »или что-то в этом роде. Это не лучшее решение (ложно предполагает, что класс может поддерживать конструктор no-arg), но это лучшее, что я могу придумать. – JMTyler

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"; 
    } 
} 

Если вы не добавить конструктор (любой) к классу компилятора добавить параметр по умолчанию не 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"); 

If I were to change the method signature of the BaseClass constructor, I would have to change all the subclasses.

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

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

public interface NameAware { 
    public String getName(); 
} 



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

Здесь B и C может унаследовали от А, который бы создал очень высокое сцепление между ними, с помощью интерфейсов муфты уменьшается, если А решает, что будет больше не будет «NameAware», другие классы не сломаются.

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

+2

Да, за исключением того, что вы больше не можете гарантировать, что ваши экземпляры были правильно инициализированы (например, имеют имена в этом конкретном случае) – ChssPly76

+0

@ ChssPly76: Да, но это, вероятно, потому, что наследование используется плохо. Я расширил свой ответ, чтобы покрыть его. – OscarRyz

0

Ваш 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"; 
    } 
} 
41

Для тех, кто 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.

+1

Только что получил эту ошибку без видимых причин в Eclipse. Затем я очистил рабочее пространство (меню Project -> Clean ...), и оно исчезло. – erickrf

-1

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

Cheers.

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"; 
    } 
} 
+0

Это позволяет легко создавать недопустимые объекты (те, у которых нет 'someString'), и, следовательно, полностью побеждает цель как конструктора. – Robert

0

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

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

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

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

-1

Я имел эту ошибку и установил ее, удалив метательного исключение из рядом метода к блоку попробовать/поймать

Например: FROM:

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

} 

TO:

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

    }catch(SQLException) 
    { 
    } 
} 
+0

Этот ответ не имеет ничего общего с ошибками компилятора для отсутствующего конструктора. – Robert

1

эта ошибка возникла из-за JRE не была установлена ​​так, пожалуйста, выполните следующие действия:


1. right clic k project -> Свойства -> Путь сборки Java -> вкладка «Вкладка« Библиотека »
2. Нажмите« Добавить библиотеку »
3. Выберите Системную библиотеку JRE -> Нажмите« Далее »
4. Выберите« Рабочее место по умолчанию jre »или« Альтернативный установленный jre »
5. нажмите отделку

+0

Гош, ОП даже не сказал, какой IDE (если есть) он использует ... – Robert

0

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