web-dev-qa-db-ja.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()メソッドを実装します( template method pattern )。

これはうまく機能しますが、サブクラスに冗長なコンストラクターがあるのは好きではありません。入力するだけでなく、維持するのが困難です。 BaseClassコンストラクターのメソッドシグネチャを変更する場合、すべてのサブクラスを変更する必要があります。

サブクラスからコンストラクターを削除すると、次のコンパイル時エラーが発生します。

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

私がやろうとしていることは可能ですか?

87
Joel

コンストラクターを持たないクラスにはdefaultコンストラクターがあるため、このエラーが発生します。このコンストラクターは引数がなく、次のコードと同等です。

public ACSubClass() {
    super();
}

ただし、BaseClassはコンストラクターを宣言するため(したがって、コンパイラーが提供するデフォルトの引数なしのコンストラクターはありません)、これは違法です-BaseClassを拡張するクラスはsuper();を呼び出すことができません。 BaseClassの引数なしのコンストラクタ。

サブクラスには基本クラスが持つコンストラクターが自動的にあると考えるかもしれないので、これはおそらく少し直感に反します。

これを回避する最も簡単な方法は、基本クラスがコンストラクターを宣言しない(したがって、デフォルトの引数なしのコンストラクターを持つ)か、宣言された引数なしのコンストラクターを(単独で、または他のコンストラクターと一緒に)持つことです。ただし、多くの場合、このアプローチは適用できません。クラスの正当なインスタンスを構築するには、コンストラクターに渡す引数が必要だからです。

143
matt b

このエラーのためにGoogleに到着し、ここに到着した場合:別の理由が考えられます。 Eclipseは、プロジェクトのセットアップ時にこのエラーを出します-システム構成の不一致。

たとえば、Java 1.7プロジェクトをEclipseにインポートし、1.7が正しくセットアップされていない場合、このエラーが発生します。その後、Project - Preference - Java - Compilerswitch to 1.6 or earlierに移動できます。またはWindow - Preferences - Java - Installed JREsに移動して、JRE 1.7インストールを追加/修正します。

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

クラスにコンストラクタ(any)を追加しない場合、コンパイラはデフォルトの引数なしのコンストラクタを追加します。

Defualt no argがsuper()を呼び出すとき;また、スーパークラスにはないため、そのエラーメッセージが表示されます。

それはそれ自身の質問についてです。

次に、答えを拡大します。

異なる値(data)を指定するサブクラス(behavior)を作成しても意味がないことをご存知ですか?!!!お願いします。

変更されるのが「名前」だけである場合、パラメータ化された単一のクラスで十分です。

したがって、これは必要ありません。

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コンストラクターのメソッドシグネチャを変更する場合、すべてのサブクラスを変更する必要があります。

それが、継承がOOシステムでは望ましくないHIGHカップリングを作成するアーティファクトである理由です。避けるべきであり、おそらく構図に置き換える必要があります。

本当にサブクラスとしてそれらが本当に必要かどうかを考えてください。そのため、多くの場合、インターフェースがinstedで使用されています。

 public interface NameAware {
     public String getName();
 }



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

ここで、BとCがAから継承している可能性があります。インターフェースを使用することで、カップリングが減少します。

もちろん、振る舞いを再利用したい場合、これは機能しません。

7
OscarRyz

JREが設定されていない場合にもこのエラーが発生する可能性があります。その場合は、プロジェクトにJREシステムライブラリを追加してみてください。

Eclipse IDEの下:

  1. メニューを開くProject-> Properties、またはPackage Explorerでプロジェクトを右クリックしてProperties( WindowsではAlt + Enter、MacではCommand + I)
  2. Javaビルドパスをクリックしてからライブラリタブをクリックします
  3. モジュールパスまたはクラスパスを選択し、ライブラリを追加...ボタンを押します
  4. JRE System Libraryを選択してからNextをクリックします
  5. ワークスペースのデフォルトJREを選択したままにして(別のオプションを選択することもできます)、完了をクリックします
  6. 最後に適用して閉じるを押します。
1
yogesh kumar

別の方法は、必要な引数を派生クラスコンストラクターの最初のステートメントとしてsuper()を呼び出すことです。

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

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

サブクラスコンストラクターの最初のステートメントとしてスーパークラスコンストラクターを呼び出さない場合、Eclipseはこのエラーを返します。

0
Sagar

baseClassにはsomeStringが必要なので、deliver oneです。
これを試して:

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

ネクロポストで申し訳ありませんが、今日この問題に直面しました。この問題に直面しているすべての人のために-彼の考えられる理由の1つ-メソッドの最初の行でsuperを呼び出さないでください。 2行目、3行目、その他の行でこのエラーが発生します。 superの呼び出しは、メソッドの最初の呼び出しである必要があります。この場合、すべてが順調です。

0
Serj.by