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


150

トピックはそれのほとんどを述べています-静的メソッドがインターフェイスで宣言できないという事実の理由は何ですか?

public interface ITest {
    public static String test();
}

上記のコードを実行すると、次のエラーが発生します(少なくともEclipseでは)。


2
Espoの回答には欠陥があるため、同意しないでください。インターフェースには、静的メソッドの実装を含めることができるクラスファイルがあるため(Javaデザイナーがこれを許可している場合)、静的メソッドの実装を解決しても問題はありません。他の静的クラスとまったく同じように機能します。
Mnementh 2008

私は一種の「エリクソン」によって与えられた答えに同意 stackoverflow.com/questions/512877/...
マーベリック

9
これはJava 8で利用できるようになる予定です。
m0skit0 2013

1
@Vadorequest GIYFとにかく、ここをチェックしてください
m0skit0

2
公式ドキュメントからのリンク:Java SEチュートリアルJava言語仕様9.2
LoganMzz

回答:


85

ここには、いくつかの問題があります。1つ目は、静的メソッドを定義せずに宣言する問題です。これは

public interface Foo {
  public static int bar();
}

そして

public interface Foo {
  public static int bar() {
    ...
  }
}

Espoが言及している理由により、1つ目は不可能です。どの実装クラスが正しい定義であるかがわかりません。

Java は後者を許可できます。そして実際、Java 8以降では、そうなります!


2
はい-それは技術的なものではなく、概念的なものです。それが私が欲しい理由です。クラスを実装することで簡単に再利用できるインターフェース内の他の「インターフェース」メソッドのみを参照するインターフェース内に静的な「実装」メソッドを持つことができるということです。しかし、インターフェイスで静的クラスを宣言して、MyInterface.Impl.doIt(MyInterface i、Object [] args){...}のようなものをそこに常駐させることができます
peterk

9
Java 8以降staticでは、メソッドをで定義できますinterface。メソッドはでなければなりませんpublic
OlivierGrégoire2014年

4
@OlivierGrégoire...そしてそれらは継承されません、それが鍵です。
ウィリアムF.ジェイムソン

1
「ほぼ同等」のROFLMAO xDでも良い答えですが、「やや似ている」と言ったほうがいいでしょう。
Timo、

44

インターフェースに静的メソッドを含めることができない理由は、Javaが静的参照を解決する方法にあります。Javaは、静的メソッドを実行しようとするときに、クラスのインスタンスを探す必要はありません。これは、静的メソッドはインスタンスに依存しないため、クラスファイルから直接実行できるためです。インターフェースのすべてのメソッドが抽象的であることを考えると、VMは、静的メソッドの背後にあるコードを見つけて実行できるようにするために、インターフェースの特定の実装を探す必要があります。これは、静的メソッド解決がどのように機能するかと矛盾し、言語に不整合をもたらします。


3
この説明は問題を説明していません。すべてのインターフェイスには独自のクラスファイルがあり、静的メソッドを含めることができます。したがって、特定の実装の検索は必要ありません。
Mnementh 2008

Javaのすべてのインターフェースタイプが独自のファイル内にあるわけではなく、JLSに準拠している必要もありません。さらに、JLSでは、クラスは常にファイルシステムと共に保存する必要があるとは規定していません。
Vlad Gudim、2009

4
@Totophil:インターフェースは単一のjava-file内にあってはなりませんが、コンパイル後は独自のclass-fileを持ちます。それは私が書いたものです。
Mnementh、2011年

18

例を挙げて質問に答えます。静的メソッドを追加したMathクラスがあるとします。このメソッドは次のように呼び出します。

Math.add(2, 3);

Mathがクラスではなくインターフェイスである場合、定義された関数はありません。そのため、Math.add(2、3)のようなことを言っても意味がありません。


11

その理由は、Javaが多重継承を許可しないという設計原理にあります。多重継承の問題は、次の例で説明できます。

public class A {
   public method x() {...}
}
public class B {
   public method x() {...}
}
public class C extends A, B { ... }

Cx()を呼び出すとどうなりますか?Ax()またはBx()が実行されますか?多重継承を持つすべての言語は、この問題を解決する必要があります。

インターフェースは、Javaである種の制限された多重継承を可能にします。上記の問題を回避するために、メソッドを持つことは許可されていません。インターフェースと静的メソッドで同じ問題を見ると:

public interface A {
   public static method x() {...}
}
public interface B {
   public static method x() {...}
}
public class C implements A, B { ... }

ここで同じ問題、Cx()を呼び出すとどうなりますか?


反対票の理由は?説明コメントがいいでしょう。
Mnementh、2011年

私はダウンボーターではありませんが、これは非静的メソッドにも有効ではありませんか?
nawfal

OK、2つの可能性があります。メソッドを実装するか、宣言するだけです。静的メソッドを実装する必要があることを理解しました。その意味で、私は私の回答で提示された問題に遭遇します。そうしないと、Espoが説明した問題にぶつかります。静的メソッドが実装されると想定していたため、理解できませんでした。このため、静的抽象メソッドを宣言することもできません。試してみてください。コンパイラーが文句を言うでしょう。
2012年

さて、実装部分を忘れてください。問題は、なぜ宣言できないのかです。はい、コンパイラは文句を言うでしょう、そしてそれはなぜ問題なのですか?あなたが答えたことはないと思います。
nawfal

1
インターフェースAが含まれていてint x(int z);、インターフェースBが含まれているよりも悪い状況はありますstring x(int x);か?x(3)インターフェイスCの意味は何ですか?
スーパーキャット2013

7

静的メソッドはインスタンスメソッドではありません。インスタンスコンテキストがないため、インターフェイスから実装することはほとんど意味がありません。


5

Java8では、インターフェイスで静的メソッドを定義することもできます。

interface X {
    static void foo() {
       System.out.println("foo");
    }
}

class Y implements X {
    //...
}

public class Z {
   public static void main(String[] args) {
      X.foo();
      // Y.foo(); // won't compile because foo() is a Static Method of X and not Y
   }
}

注:キーワードdefault / staticを明示的に使用してそれらをデフォルトメソッドおよび静的メソッドにそれぞれ指定しない場合、インターフェースのメソッドはデフォルトで引き続きパブリック抽象です。


4

ここにあなたの質問に対する非常に素晴らしく簡潔な答えがあります。(ここからリンクしたいという、とてもわかりやすい説明の仕方で私を驚かせました。)


これは質問に対する回答ではなく、よくてもコメントにする必要があります。
CubeJockey 2016年

3

インターフェースの静的メソッドはJava 8でサポートされているようですが、私の解決策はそれらを内部クラスで定義することです。

interface Foo {
    // ...
    class fn {
        public static void func1(...) {
            // ...
        }
    }
}

同じ手法をアノテーションでも使用できます。

public @interface Foo {
    String value();

    class fn {
        public static String getValue(Object obj) {
            Foo foo = obj.getClass().getAnnotation(Foo.class);
            return foo == null ? null : foo.value();
        }
    }
}

内部クラスには常にではInterface.fn...なくの形式でアクセスする必要がありますClass.fn...。そうすると、あいまいな問題を取り除くことができます。


2

インターフェイスは、ポリモーフィズムに使用されます。これは、タイプではなくオブジェクトに適用されます。したがって、(すでに述べたように)静的なインターフェースメンバーを持つことは意味がありません。


いくつかの反射的なコンテキストでは、ほとんどの場合意味があるように思われます
Cruncher '27

1

Java 8は、インターフェースに静的メソッドを含めることができる世界を変えましたが、そのための実装を提供する必要があります。

public interface StaticMethodInterface {
public static int testStaticMethod() {
    return 0;
}

/**
 * Illegal combination of modifiers for the interface method
 * testStaticMethod; only one of abstract, default, or static permitted
 * 
 * @param i
 * @return
 */
// public static abstract int testStaticMethod(float i);

default int testNonStaticMethod() {
    return 1;
}

/**
 * Without implementation.
 * 
 * @param i
 * @return
 */
int testNonStaticMethod(float i);

}


0

修飾子の不正な組み合わせ:静的および抽象

クラスのメンバーが静的として宣言されている場合、オブジェクトを作成せずに、そのクラスに限定されているクラス名で使用できます。

クラスのメンバーが抽象として宣言されている場合、クラスを抽象として宣言する必要があり、継承されたクラス(サブクラス)で抽象メンバーの実装を提供する必要があります。

静的メソッドの動作を変更するサブクラスのクラスの抽象メンバーに実装を提供する必要があります。これも、基本クラスに限定されている抽象として宣言されていますが、正しくありません


これはどのように質問に答えますか?OPは、クラスについて書いているときにインターフェースについて尋ねました。
ラッキー、

0

静的メソッドは継承できないため。したがって、それをインターフェースに配置しても無駄です。インターフェイスは基本的に、すべてのサブスクライバーが従わなければならない契約です。静的メソッドをインターフェイスに配置すると、サブスクライバーはそれを実装する必要があります。これは、静的メソッドを継承できないという事実と矛盾します。


静的メソッドは常に継承されますが、オーバーライドすることはできません。
Akki

0

Java 8、インターフェースは、今の静的メソッドを持つことができます。

たとえば、コンパレータにはstatic naturalOrder()メソッドがあります。

インターフェイスに実装を含めることができないという要件も緩和されました。インターフェースは「デフォルト」メソッドの実装を宣言できるようになりました。これは、1つの例外を除いて通常の実装と同様です。インターフェースからデフォルトの実装とスーパークラスから通常の実装の両方を継承する場合、スーパークラスの実装が常に優先されます。


ああ、神様!私たちは真面目なプログラマー(そして私、コメンター)が10歳の質問に答えます(そして私、コメントします)。
Mohamed Anees A

私は日付に気づかなかった:)
Ishara

ははは!問題ない!
Mohamed Anees A 2019

-2

おそらくコード例が役立つでしょう。私はC#を使用しますが、あなたはそれに従っていくことができるはずです。

IPayableというインターフェースがあるとしましょう

public interface IPayable
{
    public Pay(double amount);
}

これで、このインターフェースを実装する2つの具象クラスができました。

public class BusinessAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

public class CustomerAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

ここで、さまざまなアカウントのコレクションがあるとしましょう。これを行うには、IPayableタイプの汎用リストを使用します

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

次に、これらすべてのアカウントに$ 50.00を支払います。

foreach (IPayable account in accountsToPay)
{
    account.Pay(50.00);
}

これで、インターフェースが非常に便利であることがわかります。

これらは、インスタンス化されたオブジェクトでのみ使用されます。静的クラスではありません。

payを静的にした場合、accountsToPayのIPayableをループするときに、BusinessAcountまたはCustomerAccountでpayを呼び出す必要があるかどうかを判断する方法はありません。


静的メソッドがこの例で意味をなさないからといって、それらがすべての例で意味をなさないということではありません。あなたの例では、IPayableインターフェースに、追加された買掛金の数を追跡する静的メソッド「IncrementPayables」があった場合、これは実際のユースケースになります。もちろん、常に抽象クラスを使用することもできますが、それはあなたが取り組んだことではありません。あなたの例自体は、インターフェースの静的メソッドを損なうものではありません。
ランチャー2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.