Javaインターフェースで静的メソッドを定義できないのはなぜですか?


499

編集: Java 8以降、静的メソッドがインターフェースで許可されるようになりました。

次に例を示します。

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

もちろん、これは機能しません。しかし、なぜですか?

考えられる問題の1つは、電話をかけるとどうなるかです。

IXMLizable.newInstanceFromXML(e);

この場合、空のメソッド(つまり、{})を呼び出すだけでよいと思います。すべてのサブクラスは静的メソッドを実装する必要があるため、静的メソッドを呼び出すときにはすべて問題ありません。では、なぜこれができないのでしょうか。

編集:私は「Javaのやり方だから」よりも深い答えを探していると思います。

静的メソッドを上書きできない特定の技術的な理由はありますか?つまり、Javaの設計者がインスタンスメソッドをオーバーライド可能にして静的メソッドにしないことにしたのはなぜですか。

編集:私のデザインの問題は、インターフェイスを使用してコーディング規約を強制しようとしていることです。

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

  1. IXMLizableインターフェイスを実装して、それを実装するクラスをXML要素に変換できるようにしたい(ポリモーフィズムを使用して、うまく機能する)。

  2. IXMLizableインターフェイスを実装するクラスの新しいインスタンスを作成したい場合は、newInstanceFromXML(Element e)静的コンストラクターがあることが常にわかります。

インターフェースにコメントを入力する以外に、これを確実にする他の方法はありますか?


4
ところで、インターフェイスのパブリックメソッド(およびフィールド)の定義を煩雑にする必要はありません。
トム・ホーティン-タックライン09

うーん、stackoverflow.com / questions / 21817 / …の複製のようです。以前にそれを見たことがない。
マイケル・マイヤーズ

1
静的インターフェイスメソッドをどのように使用したいか、いくつかのコードを提供できますか?
Pavel Feldman、

43
これは、Java 8で可能になります。docs.oracle.com/javase/tutorial/java/IandI/...
dakshang

1
@dakshangはい、しかしそれはOPが望むことをしません。
user253751 2015

回答:


518

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

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

ここには本当に2つの質問があります。

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

インターフェースの静的メソッド

以前のバージョンではインターフェイスに静的メソッドがなかったという強力な技術的理由はありませんでした。これは、重複した質問の投稿によってうまくまとめられています。静的インターフェースメソッドは、当初は小さな言語変更と見なされていましたが、Java 7に追加するという公式の提案がありましたが予期しない複雑さのために後で削除されました。

最後に、Java 8は静的インターフェースメソッドを導入し、デフォルトの実装でオーバーライド可能なインスタンスメソッドを導入しました。ただし、インスタンスフィールドを含めることはできません。これらの機能はラムダ式サポートの一部であり、JSR 335のパートHで詳細を読むことができます

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

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

静的メソッドはコンパイル時に解決できます。動的なディスパッチは、インスタンスメソッドの場合に意味があります。コンパイラーはオブジェクトの具体的なタイプを判別できないため、呼び出すメソッドを解決できません。ただし、静的メソッドを呼び出すにはクラスが必要です。そのクラスはコンパイル時に静的に認識されるため、動的ディスパッチは不要です。

ここで何が行われているのかを理解するには、インスタンスメソッドがどのように機能するかについて、少し背景が必要です。実際の実装はかなり異なると思いますが、観察された動作を正確にモデル化するメソッドディスパッチの概念について説明します。

各クラスに、メソッドシグネチャ(名前とパラメーターの型)を実際のコードチャンクにマップしてメソッドを実装するハッシュテーブルがあるとします。仮想マシンは、インスタンスのメソッドを呼び出そうとすると、オブジェクトにクラスを照会し、要求された署名をクラスのテーブルで検索します。メソッド本体が見つかると、それが呼び出されます。それ以外の場合は、クラスの親クラスが取得され、そこで検索が繰り返されます。これは、メソッドが見つかるまで、または親クラスがなくなるまで続行され、結果としてになりNoSuchMethodErrorます。

スーパークラスとサブクラスの両方に同じメソッドシグネチャのテーブル内のエントリがある場合、サブクラスのバージョンが最初に検出され、スーパークラスのバージョンは使用されません。これは「オーバーライド」です。

ここで、オブジェクトインスタンスをスキップして、サブクラスで開始するとします。解決は上記のように進行し、一種の「オーバーライド可能な」静的メソッドを提供します。ただし、コンパイラは既知のクラスから開始するので、実行時にクラスの指定されていない型のオブジェクトをクエリするのを待つのではなく、解決はすべてコンパイル時に行われます。必要なバージョンを含むクラスを常に指定できるため、静的メソッドを「オーバーライド」する意味はありません。


コンストラクター「インターフェース」

質問に対する最近の編集に対処するためのもう少し資料があります。

の各実装に対してコンストラクタのようなメソッドを効果的に義務付けたいように思えますIXMLizable。インターフェースを使ってこれを1分間実行することを忘れて、この要件を満たすクラスがあるとします。どのように使用しますか?

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

Foo obj = Foo.newInstanceFromXML(e);

Foo新しいオブジェクトを「構築」するときは具体的な型に明示的に名前を付ける必要があるため、コンパイラーは、実際に必要なファクトリーメソッドがあることを確認できます。そうでない場合は、何ですか?私が実装することができた場合はIXMLizable、「コンストラクタ」を欠いている、と私はインスタンスを作成し、あなたのコードにそれを渡すことを、それがあるIXMLizableすべての必要なインタフェースを持ちます。

構築は実装の一部であり、インターフェースはありません。インターフェイスで正常に機能するコードは、コンストラクターを気にしません。コンストラクタを気にするコードはとにかく具体的な型を知る必要があり、インターフェースは無視できます。



12
#1の理由は多重継承でしょうか?複数のインターフェースから継承できるため、2つのインターフェースに同じ静的メソッドシグネチャが含まれていて、クラスが両方を実装してそのメソッドを呼び出した場合、Java言語の作成者が複数のクラスの継承を許可しないようにすることで、事態が複雑になる可能性があります。そもそも。メソッドの定義をまったく許可しないインターフェースについても、同じ議論が明らかになります。
shrini1000

1
@ shrini1000-いいえ、静的メソッドはコンパイル時に解決されます。あいまいさは、定数で処理されるのと同じ方法で処理できます。コンパイラエラーが発生します。しかし、Project Coinに基づく提案は、いくつかの予期せぬ困難を理由に却下されました。それらが何であったかはわかりませんが、私はそれがこれらの線に沿っていたとは思いません。
エリクソン、2011年

1
@ tgm1024はい、「コンストラクタ「インターフェース」」セクションでは、コンパイル時に既知の型を介してポリモーフィックな動作を呼び出そうとしても意味がない理由を説明しています。RESET()特定のクラスをどのように呼び出しますか?あなたは書くでしょうSomeClass.RESET()。そのため、そのAPIを記述するためのインターフェースは必要ありません。その静的。インターフェイスは、コンパイル時に具象型がわからない場合に使用されます。静的メソッドの場合はそうではありません。
エリクソン2016

2
「構築はインターフェースではなく実装の一部です。インターフェースで正常に機能するコードはコンストラクターを気にしません。」-それは明らかに真実ではありません。他の言語(Swiftなど)では、特定のコンストラクター(または静的メソッド)が実行時に存在することをインターフェイスで約束しているため、静的にT知らなくても新しいインスタンスを作成できTます。生成をJavaで指定することが不可能であるという事実は、それが意味のあることではないことを意味しません。
ラファエル

48

これは既に尋ねられて答えられました

私の答えを複製するには:

インターフェイスで静的メソッドを宣言しても意味がありません。通常の呼び出しMyInterface.staticMethod()では実行できません。実装クラスMyImplementor.staticMethod()を指定してそれらを呼び出す場合は、実際のクラスを知っている必要があるため、インターフェースにクラスが含まれているかどうかは関係ありません。

さらに重要なことに、静的メソッドは決してオーバーライドされません。

MyInterface var = new MyImplementingClass();
var.staticMethod();

staticのルールでは、varの宣言された型で定義されたメソッドを実行する必要があるとしています。これはインターフェースなので、不可能です。

"result = MyInterface.staticMethod()"を実行できないのは、MyInterfaceで定義されているメソッドのバージョンを実行する必要があるためです。しかし、それはインターフェースであるため、MyInterfaceで定義されたバージョンは存在できません。定義上、コードはありません。

これは「Javaがそのように行うため」に相当すると言えますが、実際には、決定は他の設計決定の論理的な結果であり、これも非常に正当な理由があります。


14
<T extends MyInterface>をジェネリック型パラメーターとして使用する場合、インターフェイスを介してTが.doSomething()を実行できることを保証すると便利です。
Chris Betti、2013

4
引数は理解していますが、@ Chris_Bettiに同意します(非ジェネリック型の場合でも)。コード構造によって、一部のクラスが特定の静的APIを実装するようになっていると便利です。多分それは別の概念を使用して可能である...
Juh_

@Juh_、.....または絶対に必要な場合は新しいキーワード。staticいずれにせよ、言葉のなかで不慣れな言葉だと私は信じています。だから、それだけですでに大ざっぱになっています。上記の私の例、stackoverflow.com / questions / 512877 /… {shrug}を参照してください。

3
これは真実ではないようです:「インターフェースで静的メソッドを宣言する意味は決してありません。」インスタンス化せずに情報を提供できるクラスのコレクションがあるが、この静的なクラスレベルの情報を入れるための共通のインターフェース(つまり、オーバーライド可能な静的メソッドを持つインターフェース)が必要な場合、それは有効な使用法です。属性やリフレクションなどをいじらずにクラスプロパティに関するメタ情報をキャプチャできるリフレクション++について考えてみましょう。
Jason

1
「インターフェースで静的メソッドを宣言しても意味がありません。」これは真実ではありません。システムにデフォルトのクラスリゾルバがあるとします。ContainerInjectionInterce :: create(Container $ container)メソッドを実装していることが検出されると、たとえばこの関数を使用してオブジェクトが作成されます。
user3790897

37

通常、これはFactoryパターンを使用して行われます

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);
}

public interface IXMLizable {
  public Element toXMLElement();
}

7
+1ファクトリパターンは、問題の解決策のように聞こえます。(質問にはありませんが)
pvgoddijn

ここに<T extends IXMLizable>を置くことの意味は誰かに教えてもらえますか?私はjavaを初めて使用します。
Nuwan Harshakumara Piyarathna

1
@NuwanHarshakumaraPiyarathna Tは、IXMLizableを拡張するクラスでなければなりません。これが何を意味するかをよりよく理解するためにJavaジェネリックを調べてください
エイドリアン

37

Java 8の登場により、インターフェースにデフォルトのメソッドと静的メソッドを作成できるようになりました。 docs.oracle/staticMethod

例えば:

public interface Arithmetic {

    public int add(int a, int b);

    public static int multiply(int a, int b) {
        return a * b;
    }
}
public class ArithmaticImplementation implements Arithmetic {

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = Arithmetic.multiply(2, 3);
        System.out.println(result);
    }
}

結果:6

ヒント:静的インターフェイスメソッドの呼び出しは、クラスで実装する必要はありません。確かに、これはスーパークラスの静的メソッドと同じルールがインターフェースの静的メソッドに適用されるために起こります。


これはこの質問の完璧な例です。

21

静的メソッドはサブクラスでオーバーライドできないため、抽象クラスにすることはできません。そして、インターフェースのすべてのメソッドは、事実上、抽象的です。


2
常に各タイプに静的なインターフェイスメソッドを実装させることができます。型クラス、誰か?
MichaelGG

16
自分の外に出て、質問に答えてください:静的メソッドをオーバーライドできないのはなぜですか?静的メソッドをオーバーライドできる場合、どのように見えますか?それらで何ができますか?この答えは基本的に「できないからできない」です。
エリクソン2009

10

Javaインターフェースで静的メソッドを定義できないのはなぜですか?

実際、Java 8ではできます。

Java docに従って:

静的メソッドは、オブジェクトではなく、それが定義されているクラスに関連付けられているメソッドです。クラスのすべてのインスタンスはその静的メソッドを共有します

Java 8では、インターフェースはデフォルトのメソッド静的メソッドを持つことができます。これにより、ライブラリでヘルパーメソッドを整理しやすくなります。インターフェースに固有の静的メソッドを、別のクラスではなく同じインターフェースに保持できます。

デフォルトの方法の例:

list.sort(ordering);

の代わりに

Collections.sort(list, ordering);

静的メソッドの例(ドキュメント自体から):

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

6

インターフェイスは、本質的にクラスではなくオブジェクトインスタンスに関連付けられているポリモーフィズムに関係しています。したがって、インターフェイスのコンテキストではstaticは意味がありません。


明確で簡潔なロジック。よく置きます。
Oke Uwechue

6

まず、言語に関するすべての決定は、言語の作成者が行った決定です。ソフトウェアエンジニアリング、言語定義、コンパイラ/インタプリタの記述の世界では、静的メソッドをインターフェイスの一部にすることはできないと言っていることはありません。私はいくつかの言語を作成し、それらのためにコンパイラーを作成しました-それはただ座って意味のあるセマンティクスを定義するだけです。インターフェイスの静的メソッドのセマンティクスは、コンパイラーが実行時までメソッドの解決を延期しなければならない場合でも、非常に明確であると私は主張します。

第2に、静的メソッドを使用しているということは、静的メソッドを含むインターフェイスパターンを使用する正当な理由があることを意味します。

最も可能性が高い正解は、言語が定義された時点では、インターフェースの静的メソッドに対する必要性が認識されていなかったことです。Javaは長年にわたって大幅に成長しており、これは明らかに関心を集めているアイテムです。Java 7について検討されたことは、言語の変更につながる可能性のある関心レベルにまで上昇したことを示しています。サブクラスインスタンスの静的変数にアクセスするために非静的ゲッターメソッドを呼び出すことができるように、オブジェクトをインスタンス化する必要がなくなったとき、私は1つに満足します...


5

静的メソッドはインスタンスメソッドのように仮想ではないので、Java設計者はそれらをインターフェイスに含めたくないと判断したと思います。

ただし、静的メソッドを含むクラスをインターフェース内に置くことができます。あなたはそれを試すことができます!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}

5
  • 「静的メソッドをオーバーライドできない特別な理由はありますか?」

定義を記入して、あなたのためにその質問を言い換えましょう。

  • 「コンパイル時に解決されるメソッドが実行時に解決できない特別な理由はありますか?」

または、より完全に入力するには、インスタンスなしでメソッドを呼び出したいが、クラスを知っている場合、持っていないインスタンスに基づいてクラスを解決するにはどうすればよいですか。


3

いくつかの回答では、オーバーライド可能な静的メソッドの概念に関する問題が議論されています。ただし、使用したいパターンに出くわすこともあります。

たとえば、私は値オブジェクトを持つオブジェクトリレーショナルレイヤーを操作しますが、値オブジェクトを操作するためのコマンドも持っています。さまざまな理由により、各値オブジェクトクラスは、フレームワークがコマンドインスタンスを検索できるようにするいくつかの静的メソッドを定義する必要があります。たとえば、次のようにしてPersonを作成します。

cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();

そして、あなたが行うIDでPersonをロードするには

cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();

これはかなり便利ですが、問題があります。特に静的メソッドの存在は、インターフェースで強制することはできません。インターフェースのオーバーライド可能な静的メソッドは、何らかの方法で機能することができれば、まさに私たちが必要とするものです。

EJBはホームインターフェースを持つことでこの問題を解決します。各オブジェクトはそのホームを見つける方法を知っており、ホームには「静的」メソッドが含まれています。このようにして、「静的」メソッドを必要に応じてオーバーライドでき、Beanのインスタンスに適用されないメソッドで通常の(「リモート」と呼ばれます)インターフェースを混乱させることはありません。通常のインターフェースで「getHome()」メソッドを指定するだけです。Homeオブジェクト(シングルトンの場合もある)のインスタンスを返し、呼び出し元はすべてのPersonオブジェクトに影響する操作を実行できます。


3

コメント EDIT: As of Java 8, static methods are now allowed in interfaces.

正しい、静的メソッドはJava 8がインターフェースで許可されているためですが、あなたの例はまだ機能しません。静的メソッドを単に定義することはできません。それを実装する必要があります。そうしないと、コンパイルエラーが発生します。


2

まあ、ジェネリックがないと、静的メソッドの呼び出しはすべてコンパイル時に解決されるため、静的インターフェイスは役に立ちません。したがって、それらの実際の使用はありません。

ジェネリックでは、デフォルトの実装の有無にかかわらず、それらを使用できます。当然、オーバーライドなどが必要になります。しかし、私の推測では、そのような使用法は非常にオブジェクト指向ではなかったため(他の回答は鈍感に指摘されているため)、それらを有効に実装するために必要な努力に見合う価値があるとは見なされませんでした。


1
ジェネリックスはこれと何をしているのですか?インターフェイスの静的メソッドはまだ実行できません。
DJクレイワース2009

まず、それは実装の決定です。しかし、私は彼がインターフェイスで静的メソッドを呼び出したくないと思っています(彼はクラスを使用することができます)。しかし、代わりに、型クラスのようなものや、型パラメーターを超えないものが必要です。実際、彼の最新の編集はこれをさらに明確に示しています。
MichaelGG

2
Why can't I define a static method in a Java interface?

インターフェースのすべてのメソッドは明示的に抽象的であり、静的メソッドは抽象的ではないため、静的として定義することはできません。


1

インターフェースを静的に逆参照することはできませんISomething.member。インターフェイスは常に、インターフェイスのサブクラスのインスタンスを参照する変数を介して逆参照されます。したがって、インターフェース参照は、そのサブクラスのインスタンスがないと、それがどのサブクラスを参照しているかを決して知ることができません。

したがって、インターフェイスの静的メソッドに最も近いのは、「this」を無視する非静的メソッドです。つまり、インスタンスの非静的メンバーにはアクセスしません。低レベルの抽象化では、すべての非静的メソッド(vtableでの検索後)は、実際には、「this」を暗黙の仮パラメーターとして取るクラススコープを持つ単なる関数です。その概念の証拠として、ScalaのシングルトンオブジェクトとJavaとの相互運用性をご覧ください。したがって、すべての静的メソッドは、「this」パラメーターをとらないクラススコープを持つ関数です。したがって、通常、静的メソッドは静的に呼び出すことができますが、前述のとおり、インターフェースには実装がありません(抽象的です)。

したがって、インターフェイスの静的メソッドに最も近いものを取得するには、非静的メソッドを使用し、非静的インスタンスメンバーにはアクセスしないでください。aを(コンパイル時に)静的にリンクする方法がないため、他の方法でパフォーマンスを向上させることはできませんISomething.member()。インターフェースの静的メソッドの唯一の利点は、暗黙の「this」を入力しない(つまり無視する)ため、非静的インスタンスメンバーへのアクセスが許可されないことです。これは、「this」にアクセスしない関数が不変であり、その包含クラスに関して読み取り専用ではないことを暗黙的に宣言します。しかし、インターフェースでの「静的」の宣言ISomethingそれにアクセスしようとした人々を混乱させISomething.member()コンパイラエラーが発生します。コンパイラエラーが十分に説明的である場合、ここで行っているように(そしてほとんどがファクトリメソッド)、非静的メソッドを使用して目的を達成するように人々を教育することを試みるよりも良いと思います(3回繰り返されました)このサイトでのQ&Aタイム)なので、多くの人にとって直感的でない問題であることは明らかです。正しく理解するためにしばらく考えなければなりませんでした。

インターフェースで変更可能な静的フィールドを取得する方法は、インターフェースで非静的なゲッターメソッドとセッターメソッドを使用して、サブクラスの静的フィールドにアクセスすることです。傍注、どうやら不変のstaticは、Javaインターフェースでを使用して宣言できますstatic final


0

インターフェースは、クラスが提供するもののリストを提供するだけであり、それらの実際の実装ではありません。これが静的アイテムです。

静的が必要な場合は、抽象クラスを使用してそれを継承し、そうでない場合は静的を削除します。

お役に立てば幸いです。


2
まあ、理論的には、静的な動作を含むようにインターフェイスを定義できます。つまり、「このインターフェイスの実装には、このシグネチャを持つ静的メソッドfoo()があります」という実装で、実装は特定のクラスに任せます。この動作が役立つ状況に遭遇しました。
Rob、

0

静的メソッドはクラスのインスタンスではなくクラスに属し、インターフェースはクラスではないため、インターフェースで静的メソッドを定義することはできません。詳細はこちら。

ただし、必要に応じてこれを行うことができます:

public class A {
  public static void methodX() {
  }
}

public class B extends A {
  public static void methodX() {
  }
}

この場合、2つのクラスがあり、methodX()と呼ばれる2つの異なる静的メソッドがあります。


0

できるとしましょう。この例を考えてみましょう:

interface Iface {
  public static void thisIsTheMethod();
}

class A implements Iface {

  public static void thisIsTheMethod(){
    system.out.print("I'm class A");
  }

}

class B extends Class A {

  public static void thisIsTheMethod(){
    System.out.print("I'm class B");
  } 
}

SomeClass {

  void doStuff(Iface face) {
    IFace.thisIsTheMethod();
    // now what would/could/should happen here.
  }

}

1
「私はクラスA」と出力します。ただし、入力したA.thisIsTheMethod()場合は「I'm class B」と出力されます。
cdmckay 2009

しかし、インターフェイスでメソッドを呼び出すoyrは、どのメソッドを呼び出す必要があるのか​​(またはコンパイラ)を知ることができますか?(厳密には、Ifaceを実装するクラスが増える可能性があります
pvgoddijn

申し訳ありませんが、私は言うB.thisIsTheMethod()つもりでした:ただし、入力すると、「私はクラスB」と出力されます。
cdmckay 2009

私はIFace.thisIsTHeMethodを故意に言ったのは、そこに問題があるためです。(宣言されていても)未定義の動作なしにインターフェイスで呼び出すことはできません
pvgoddijn '20 / 02/20

0

実装できるものは、静的インターフェースです(インターフェースの静的メソッドではありません)。特定の静的インターフェイスを実装するすべてのクラスは、対応する静的メソッドを実装する必要があります。あなたはクラスクラスから静的インターフェースSIを取得することができます

SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI
// alternatively if the class is known at compile time
SI si = Someclass.static.SI; // either compiler errror or not null

その後、あなたは呼び出すことができますsi.method(params)。コンパイル時の不明なクラスからSI静的メソッドの実装を取得(または実装のチェック)できるため、これは(たとえば、ファクトリデザインパターンの場合)役立ちます。動的ディスパッチが必要であり、(静的インターフェースを介して呼び出された場合)クラスを拡張することにより、クラスの静的メソッド(最終でない場合)をオーバーライドできます。明らかに、これらのメソッドはクラスの静的変数にしかアクセスできません。


0

Java 8がこの問題を解決することはわかっていますが、インターフェイスで静的メソッドを指定できると便利な、現在取り組んでいる(Java 7を使用するようにロックされている)シナリオを採用すると思いました。

さまざまな理由で値を評価するヘルパーメソッドと共に「id」フィールドと「displayName」フィールドを定義した列挙型定義がいくつかあります。インターフェースを実装することで、getterメソッドが配置されていることを確認できますが、静的ヘルパーメソッドは配置されていません。列挙型であるため、ヘルパーメソッドを継承された抽象クラスなどにオフロードする明確な方法がないため、メソッドを列挙型自体で定義する必要があります。また、これは列挙型であるため、インスタンス化されたオブジェクトとして実際に渡してインターフェイスタイプとして扱うことはできませんが、インターフェイスを通じて静的ヘルパーメソッドの存在を要求できることは、私が気に入っている点です。 Java 8でサポートされています。

これが私のポイントを示すコードです。

インターフェース定義:

public interface IGenericEnum <T extends Enum<T>> {
    String getId();
    String getDisplayName();
    //If I was using Java 8 static helper methods would go here
}

1つの列挙型定義の例:

public enum ExecutionModeType implements IGenericEnum<ExecutionModeType> {
    STANDARD ("Standard", "Standard Mode"),
    DEBUG ("Debug", "Debug Mode");

    String id;
    String displayName;

    //Getter methods
    public String getId() {
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    //Constructor
    private ExecutionModeType(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }

    //Helper methods - not enforced by Interface
    public static boolean isValidId(String id) {
        return GenericEnumUtility.isValidId(ExecutionModeType.class, id);
    }

    public static String printIdOptions(String delimiter){
        return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter);
    }

    public static String[] getIdArray(){
        return GenericEnumUtility.getIdArray(ExecutionModeType.class);
    }

    public static ExecutionModeType getById(String id) throws NoSuchObjectException {
        return GenericEnumUtility.getById(ExecutionModeType.class, id);
    }
}

一般的な列挙型ユーティリティの定義:

public class GenericEnumUtility {
    public static <T extends Enum<T> & IGenericEnum<T>> boolean isValidId(Class<T> enumType, String id) {       
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(enumOption.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String printIdOptions(Class<T> enumType, String delimiter){
        String ret = "";
        delimiter = delimiter == null ? " " : delimiter;

        int i = 0;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(i == 0) {
                ret = enumOption.getId();
            } else {
                ret += delimiter + enumOption.getId();
            }           
            i++;
        }

        return ret;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String[] getIdArray(Class<T> enumType){
        List<String> idValues = new ArrayList<String>();

        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            idValues.add(enumOption.getId());
        }

        return idValues.toArray(new String[idValues.size()]);
    }

    @SuppressWarnings("unchecked")
    public static <T extends Enum<T> & IGenericEnum<T>> T getById(Class<T> enumType, String id) throws NoSuchObjectException {
        id = id == null ? "" : id;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(id.equals(enumOption.getId())) {
                return (T)enumOption;
            }
        }

        throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , ")));
    }
}

0

静的メソッドがインターフェイスで許可されているとしましょう:*それらはすべての実装クラスにそのメソッドを宣言することを強制します。*インターフェイスは通常、オブジェクトを介して使用されるため、それらに対して有効なメソッドは非静的メソッドのみです。*特定のインターフェースを知っているクラスは、その静的メソッドを呼び出すことができます。したがって、実装クラスの静的メソッドはその下で呼び出されますが、呼び出し元クラスはどちらを呼び出すかわかりません。それを知る方法は?それを推測するインスタンス化はありません!

インターフェイスは、オブジェクトを操作するときに使用されると考えられていました。このようにして、オブジェクトは特定のクラスからインスタンス化されるため、この最後の問題は解決されます。呼び出し側のクラスは、インスタンス化が3番目のクラスによって行われる可能性があるため、どの特定のクラスであるかを知る必要はありません。したがって、呼び出し元のクラスはインターフェースのみを認識します。

これを静的メソッドに拡張したい場合は、実装クラスを指定してから、呼び出し元クラスに参照を渡すことができます。これは、インターフェイスの静的メソッドを介してクラスを使用できます。しかし、この参照とオブジェクトの違いは何ですか?クラスが何であるかを表すオブジェクトが必要です。これで、オブジェクトは古いクラスを表し、古い静的メソッドを含む新しいインターフェースを実装できます-それらは現在非静的です。

メタクラスはこの目的に役立ちます。Javaクラスのクラスを試すことができます。しかし問題は、Javaがこれに対して十分な柔軟性を持たないことです。インターフェイスのクラスオブジェクトでメソッドを宣言することはできません。

これはメタ問題です-お尻をする必要があるとき

..何とか何とか

とにかく簡単な回避策があります-同じロジックでメソッドを非静的にします。しかし、その後、メソッドを呼び出すオブジェクトを最初に作成する必要があります。


0

これを解決するには:エラー:メソッド本体が欠落しているか、抽象静的void main(String [] args);を宣言します。

interface I
{
    int x=20;
    void getValue();
    static void main(String[] args){};//Put curly braces 
}
class InterDemo implements I
{
    public void getValue()
    {
    System.out.println(x);
    }
    public static void main(String[] args)
    {
    InterDemo i=new InterDemo();
    i.getValue();   
    }

}

出力:20

これで、インターフェイスで静的メソッドを使用できます


1
しかし、それは役に立たない。インターフェースに静的メソッドを定義しても、そのようなインターフェースを実装するクラスにそれ以上の定義は適用されません。静的メソッドをインターフェイスIから完全に削除すると、コードは問題なくコンパイルおよび実行されます。つまり、InterDemoクラスでIインターフェイスのメインメソッドをオーバーライドするのではなく、同じシグネチャで新しいメソッドを作成するだけです。
Fran Marzoa

-2

私はあなたがそれらを必要としないので、javaには静的インターフェースメソッドがないと思います。あなたはあなたがそう思うかもしれませんが... ...どのように使いますか?あなたがそれらを好きにしたいなら

MyImplClass.myMethod()

その場合、それをインターフェースで宣言する必要はありません。あなたがそれらを好きにしたいなら

myInstance.myMethod()

その場合、それは静的であってはなりません。実際に最初の方法を使用するが、各実装にそのような静的メソッドを強制する場合、それは実際にはコーディング規則であり、インターフェースを実装するインスタンスと呼び出しコード間の規約ではありません。

インターフェイスを使用すると、インターフェイスを実装するクラスのインスタンスと呼び出しコードの間のコントラクトを定義できます。また、Javaはこの契約に違反していないことを確認するのに役立ちます。そのため、これに依存して、どのクラスがこの契約を実装するかを心配する必要はありません。「契約に署名した人」で十分です。静的インターフェースの場合、コード

MyImplClass.myMethod()

は、各インターフェースの実装にこのメソッドが含まれているという事実に依存していないため、確実に動作させるためにjavaは必要ありません。


-5

インターフェイスの静的メソッドの必要性は何ですか?静的メソッドは、オブジェクトのインスタンスを作成する必要がない場合に基本的に使用されます。インターフェイスの全体的なアイデアは、概念から転用する静的メソッドの導入でOOPの概念を導入することです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.