なぜJavaクラスは抽象メソッドを持つことができるように抽象フィールドを持つことができますか?
たとえば、同じ抽象基本クラスを拡張する2つのクラスがあります。これらの2つのクラスにはそれぞれ、ストリング定数を除いて同一のメソッドがあります。ストリング定数は、エラーメッセージである場合があります。フィールドを抽象化できる場合、この定数を抽象化して、メソッドを基本クラスに引き上げることができます。代わりに、この場合はgetErrMsg()
と呼ばれる抽象メソッドを作成して、Stringを返し、2つの派生クラスでこのメソッドをオーバーライドしてから、メソッドをプルすることができます(抽象メソッドを呼び出す方法)。
そもそもフィールドを抽象化できなかったのはなぜですか? Javaはこれを許可するように設計されていますか?
コンストラクタ(テストされていないコード)で初期化された抽象クラスの最終フィールドを使用して、説明したことを実行できます。
abstract class Base {
final String errMsg;
Base(String msg) {
errMsg = msg;
}
abstract String doSomething();
}
class Sub extends Base {
Sub() {
super("Sub message");
}
String doSomething() {
return errMsg + " from something";
}
}
子クラスがスーパーコンストラクターを介してfinalを初期化することを「忘れる」場合、コンパイラは 警告 エラー。抽象メソッドが実装されていない場合と同じです。
私はその中に意味がありません。関数を抽象クラスに移動し、保護されたフィールドをオーバーライドできます。これが定数で機能するかどうかはわかりませんが、効果は同じです:
public abstract class Abstract {
protected String errorMsg = "";
public String getErrMsg() {
return this.errorMsg;
}
}
public class Foo extends Abstract {
public Foo() {
this.errorMsg = "Foo";
}
}
public class Bar extends Abstract {
public Bar() {
this.errorMsg = "Bar";
}
}
あなたのポイントは、サブクラスでerrorMsg
の実装/オーバーライド/何でも強制したいということですか?基本クラスにメソッドを持ちたいだけで、そのフィールドをどのように扱うか分からないと思った。
明らかにcouldはこれを許可するように設計されていますが、カバーの下では動的ディスパッチを行う必要があるため、メソッド呼び出しを行う必要があります。 Javaの設計(少なくとも初期の頃)は、ある程度まで、最小限にしようとする試みでした。つまり、デザイナーは、既に言語に含まれている他の機能によって簡単にシミュレートできる場合、新しい機能の追加を避けようとしました。
別のオプションは、フィールドを基本クラスでパブリック(必要に応じて最終)として定義し、現在使用されているサブクラスに応じて、基本クラスのコンストラクターでそのフィールドを初期化することです。循環依存を導入するという点で、少し怪しいです。ただし、少なくとも変更できる依存関係ではありません。つまり、サブクラスは存在するかどうかにかかわらず、サブクラスのメソッドまたはフィールドはfield
の値に影響を与えることはできません。
public abstract class Base {
public final int field;
public Base() {
if (this instanceof SubClassOne) {
field = 1;
} else if (this instanceof SubClassTwo) {
field = 2;
} else {
// assertion, thrown exception, set to -1, whatever you want to do
// to trigger an error
field = -1;
}
}
}
タイトルを読んで、抽象的なインスタンスメンバーを参照していると思いました。そして、私はそれらの多くの使用を見ることができませんでした。しかし、抽象静的メンバーはまったく別の問題です。
私はJavaで次のようなメソッドを宣言できることをしばしば望んでいました。
_public abstract class MyClass {
public static abstract MyClass createInstance();
// more stuff...
}
_
基本的に、親クラスの具体的な実装は、特定のシグネチャを持つ静的ファクトリメソッドを提供することを主張したいと思います。これにより、Class.forName()
を使用して具象クラスへの参照を取得でき、選択した規則で確実に構築できるようになります。