1. ホーム
  2. java

[解決済み] Javaインターフェースでスタティックメソッドを定義できないのはなぜですか?

2022-03-18 10:11:49

質問

EDITです。 Java 8 では、静的メソッドはインターフェースで使用できるようになりました。

以下はその例です。

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

もちろん、これではうまくいきません。 でも、なぜダメなのか?

考えられる問題のひとつは、電話をかけたときに何が起こるか、ということです。

IXMLizable.newInstanceFromXML(e);

この場合、空のメソッド(つまり{})を呼び出せばいいと思うんです。 全てのサブクラスは強制的にスタティックメソッドを実装することになるので、スタティックメソッドを呼び出しても全て問題ないでしょう。 では、なぜこれができないのでしょうか?

EDITです。 Javaはそういうものだから"よりも深い答えを探しているのでしょう。

静的メソッドを上書きできないのは、技術的に何か特別な理由があるのでしょうか?つまり、なぜJavaの設計者はインスタンスメソッドを上書き可能にし、スタティックメソッドを上書きしないことにしたのでしょうか?

EDITです。 私の設計の問題は、コーディング規約を強制するためにインターフェイスを使おうとしていることです。

つまり、インターフェイスの目的は2つあるのです。

  1. IXMLizableインターフェースを実装したクラスをXML要素に変換できるようにしたい(ポリモーフィズムを使用、問題なく動作)。

  2. IXMLizable インターフェースを実装したクラスの新しいインスタンスを作りたい人は、 newInstanceFromXML(Element e) 静的コンストラクタが存在することを常に知っていることになります。

これを確実にする方法は、インターフェイスにコメントを入れる以外にあるのでしょうか?

どのように解決するのですか?

Java 8 では静的インターフェースメソッドを許可

Java 8 では、インターフェイス できること は静的メソッドを持ちます。また、具体的なインスタンスメソッドを持つことができますが、インスタンスフィールドを持つことはできません。

ここで2つの質問があります。

  1. なぜ、昔はインターフェースに静的メソッドを含めることができなかったのでしょうか?
  2. なぜスタティックメソッドはオーバーライドできないのですか?

インターフェースにおける静的メソッド

以前のバージョンでは、インターフェイスに静的メソッドを持たせることができない強い技術的な理由はありませんでした。これは 投稿者がうまくまとめています。 の重複した質問です。静的インターフェースメソッドは、当初は 小さな言語の変化です。 があり、その後 公式提案 をJava 7で追加することを決定しましたが、その後 は、予期せぬ事態が発生したため、中止となりました。

最後に、Java 8 では静的なインターフェース・メソッドと、デフォルトの実装を持つオーバーライド可能なインスタンス・メソッドが導入されました。しかし、まだインスタンスフィールドを持つことはできません。これらの機能はラムダ式のサポートの一部です。 JSR335のパートHです。

静的メソッドのオーバーライド

2番目の質問に対する答えは、もう少し複雑です。

静的メソッドは、コンパイル時に解決可能です。動的ディスパッチは、コンパイラがオブジェクトの具体的な型を決定できないインスタンスメソッドの場合に意味があります。しかし、静的メソッドを呼び出すにはクラスが必要であり、そのクラスは既知なので 静的 -コンパイル時に動的なディスパッチは必要ない。

ここで何が起こっているのかを理解するためには、インスタンスメソッドがどのように動作するのかについて、少し背景を知る必要があります。実際の実装はかなり違うと思いますが、観測された挙動を正確にモデル化した私のメソッドディスパッチの考え方を説明しましょう。

各クラスには、メソッドのシグネチャ(名前とパラメータの型)を、メソッドを実装するための実際のコードの塊にマッピングするハッシュテーブルがあると仮定してください。仮想マシンがインスタンス上でメソッドを呼び出そうとすると、オブジェクトにそのクラスを問い合わせ、要求されたシグネチャをクラスのテーブルで探します。メソッド本体が見つかれば、それが呼び出されます。そうでなければ、そのクラスの親クラスを取得し、そこで検索を繰り返す。これは、メソッドが見つかるか、親クラスがなくなるまで続けられますが、その結果 NoSuchMethodError .

スーパークラスとサブクラスの両方に同じメソッド署名のエントリーがある場合、サブクラスのバージョンが最初に見つかり、スーパークラスのバージョンは決して使用されません - これは "オーバーライド"です。

ここで、オブジェクトのインスタンスをスキップして、サブクラスから始めるとします。解決は上記のように進み、一種の "overridable"静的メソッドを得ることができます。しかし、この解決はすべてコンパイル時に行われます。なぜなら、コンパイラは既知のクラスから始めるので、実行時に未指定の型のオブジェクトにそのクラスを問い合わせるのを待つ必要はないからです。静的メソッドをオーバーライドする意味はありません。なぜなら、いつでも必要なバージョンを含むクラスを指定することができるからです。


コンストラクタ "インターフェース"

先日の質問の編集に対応するため、少し資料を増やします。

の各実装に対してコンストラクタのようなメソッドを実質的に義務付けたいようですね。 IXMLizable . インターフェイスでこれを強制するのはちょっと忘れて、この要件を満たすいくつかのクラスがあると仮定してください。あなたならどう使いますか?

class Foo implements IXMLizable<Foo> {
  public static Foo newInstanceFromXML(Element e) { ... }
}

Foo obj = Foo.newInstanceFromXML(e);

具象型の名前を明示的に指定する必要があるため Foo 新しいオブジェクトを構築するときに、コンパイラはそのオブジェクトが本当に必要なファクトリーメソッドを持っているかどうかを確認することができます。もし、そうでなかったら、どうなるんだ?もし私が IXMLizable コンストラクタを持たないコードでインスタンスを生成し、それをあなたのコードに渡すと、それは アン IXMLizable を、必要なインターフェイスをすべて備えています。

施工は実装の一部です。 インターフェイスではありません。インターフェイスでうまく動作するコードは、コンストラクタを気にしません。コンストラクタを気にするコードは具象型を知る必要があり、インターフェースは無視することができます。