ここでは、インターフェイス内で静的メソッドを定義できない理由についていくつか質問がありますが、基本的な矛盾に対処するものはありません:静的メソッドではなく、インターフェイス内で静的フィールドと静的内部型を定義できるのはなぜですか?
静的な内部型は、おそらく公正な比較ではありません。これは、新しいクラスを生成する単なる構文上のシュガーですが、なぜメソッドではなくフィールドなのでしょうか?
インターフェース内の静的メソッドに対する議論は、JVMが使用する仮想テーブル解決戦略を破るということですが、静的フィールドにも同様に適用すべきではありません。つまり、コンパイラーはそれをインライン化するだけですか?
一貫性は私が望んでいるものであり、Javaはインターフェース内のどのフォームの静的もサポートしていないか、一貫性があり許可されている必要があります。
公式提案 が作成され、Java 7.のインターフェースで静的メソッドを許可します。この提案は Project Coin 。
私の個人的な意見は、それは素晴らしいアイデアだということです。実装には技術的な困難はなく、非常に論理的で合理的なことです。 Project Coinには、neverがJava言語の一部になることを望んでいますが、これは1つです。たとえば、 Collections
クラスには、List
実装を操作するための静的メソッド があります;これらは、 List
インターフェイス。
更新:Java Posse Podcast#234、 Joe D'arcyは提案を簡潔に言及し、 「複雑」であり、おそらくプロジェクトコインの下では入らないでしょう。
更新:彼らはJava 7、Java 8は、インターフェースで static関数をサポートします。
私はこの理論で私のペット理論に行きます。つまり、この場合の一貫性の欠如は、デザインや必要性ではなく利便性の問題であるということです。 。
静的フィールドは、(a)JDK 1.0にあり、JDK 1.0で多くの危険な決定が行われたため、および(b)インターフェイスの静的最終フィールドが最も近いものですJavaその時の定数。
インターフェースの静的内部クラスは、それが純粋な構文上の糖だから許可されました-内部クラスは、実際には親クラスとは何の関係もありません。
そのため、静的なメソッドは、それを行うための説得力のある理由がないという理由だけで許可されていません。一貫性は現状を変えるほど強力ではありません。
もちろん、これは将来のJLSバージョンでは何も壊さずに許可される可能性があります。
インターフェイスで静的メソッドを宣言するポイントはありません。通常の呼び出しMyInterface.staticMethod()では実行できません。 (編集:最後の文は一部の人々を混乱させたので、MyClass.staticMethod()を呼び出すと、MyClassでstaticMethodの実装が正確に実行されます。実際のクラスを知る必要があるため、インターフェイスに含まれているかどうかは関係ありません。
さらに重要なことに、静的メソッドは決してオーバーライドされません。
MyInterface var = new MyImplementingClass();
var.staticMethod();
staticのルールでは、varの宣言された型で定義されたメソッドを実行する必要があるとされています。これはインターフェースであるため、これは不可能です。
もちろん、メソッドから静的キーワードをいつでも削除できます。すべて正常に動作します。インスタンスメソッドから呼び出された場合、いくつかの警告を抑制する必要があります。
以下のコメントのいくつかに答えるために、「result = MyInterface.staticMethod()」を実行できない理由は、MyInterfaceで定義されたバージョンのメソッドを実行する必要があるためです。しかし、インターフェースであるため、MyInterfaceで定義されたバージョンは存在できません。定義によるコードはありません。
インターフェイスの目的は、実装を提供せずにコントラクトを定義することです。したがって、静的メソッドをオーバーライドすることはできないため、インターフェイスに既に実装が必要であるため、静的メソッドを使用することはできません。フィールドに関しては、静的final fields
のみが許可されます。これは、本質的に定数です(1.5+では、インターフェイスに列挙型を含めることもできます)。定数は、マジックナンバーなしでインターフェイスを定義するのに役立ちます。
ところで、静的な最終フィールドのみが許可されているため、インターフェイスのフィールドにstatic final
修飾子を明示的に指定する必要はありません。
これは古いスレッドですが、これはすべてにとって非常に重要な質問です。今日だけこれに気づいたので、私はそれをよりきれいな方法で説明しようとしています:
インターフェイスの主な目的は、実装できないものを提供することです。
許可される静的メソッド
次に、interfaceName.staticMethodName()を使用してそのメソッドを呼び出すことができますが、これは実装されていないメソッドであり、何も含まれていません。したがって、静的メソッドを許可することは無意味です。したがって、彼らはこれをまったく提供しません。
静的フィールドが許可されます
フィールドは実装可能でないため、実装可能であるということは、フィールドで論理演算を実行できないことを意味し、フィールドで演算を実行できます。したがって、フィールドの動作を変更していないため、許可されています。
内部クラスは許可されています
コンパイル後、Innerクラスの異なるクラスファイルが作成されるとInterfaceName $ InnerClassName.classとなるため、内部クラスが許可されます。したがって、基本的にはインターフェイスではなく異なるエンティティで実装を提供します。したがって、内部クラスでの実装が提供されます。
これが役立つことを願っています。
Java言語設計者はそのように望んでいませんでした。技術的な観点からは、静的メソッドを許可することは理にかなっています。インターフェースに静的メソッドがあり、メソッドを呼び出したりインターフェースを使用したりしても問題なく動作するはずのバイトコードを「手作り」できると想定していますが、テストしていません。通常どおり。
実際、誰かが静的メソッドの恩恵を受けることができる理由が時々あります。これらは、インターフェイスを実装するクラスのファクトリメソッドとして使用できます。たとえば、これが現在openjdkにコレクションインターフェイスとコレクションクラスがある理由です。そのため、常に回避策があります-静的メソッドの「名前空間」として機能するプライベートコンストラクターを別のクラスに提供します。
Java 5より前は、静的フィールドの一般的な使用法は次のとおりでした。
interface HtmlConstants {
static String OPEN = "<";
static String SLASH_OPEN = "</";
static String CLOSE = ">";
static String SLASH_CLOSE = " />";
static String HTML = "html";
static String BODY = "body";
...
}
public class HtmlBuilder implements HtmlConstants { // implements ?!?
public String buildHtml() {
StringBuffer sb = new StringBuffer();
sb.append(OPEN).append(HTML).append(CLOSE);
sb.append(OPEN).append(BODY).append(CLOSE);
...
sb.append(SLASH_OPEN).append(BODY).append(CLOSE);
sb.append(SLASH_OPEN).append(HTML).append(CLOSE);
return sb.toString();
}
}
つまり、HtmlBuilderは各定数を修飾する必要がないため、[〜#〜] open [〜 #〜]HtmlConstants.OPENの代わりに
このように道具を使用すると、最終的に混乱します。
Java 5)では、同じ効果を得るためのimport static構文があります。
private final class HtmlConstants {
...
private HtmlConstants() { /* empty */ }
}
import static HtmlConstants.*;
public class HtmlBuilder { // no longer uses implements
...
}
なぜ静的メソッドなのか不思議に思うことがよくあります。それらには用途がありますが、パッケージ/名前空間レベルのメソッドは、おそらく静的メソッドの使用目的の80をカバーします。
2つの主な理由が思い浮かびます。
Javaの静的メソッドはサブクラスによってオーバーライドできません。これは静的フィールドよりもメソッドにとってはるかに大きな問題です。実際には、サブクラスのフィールドをオーバーライドすることすら望んでいません私は常にメソッドをオーバーライドしているので、静的メソッドを使用すると、インターフェイスを実装するクラスがそのメソッドの独自の実装を提供できなくなり、インターフェイスを使用する目的が大幅に損なわれます。
インターフェイスにはコードが含まれていません。それが抽象クラスの目的です。インターフェースの重要なポイントは、特定のメソッドのセットをすべて持っている、おそらく無関係なオブジェクトについて話すことです。実際にこれらのメソッドの実装を提供することは、インターフェースの意図の範囲外です。
静的メソッドはクラスに関連付けられています。 Javaでは、インターフェイスは技術的にはクラスではなく、タイプですが、クラスではありません(したがって、キーワードは実装され、インターフェイスはObjectを拡張しません)。インターフェイスはクラスではないため、アタッチする実際のクラスがないため、静的メソッドを持つことはできません。
InterfaceName.classを呼び出して、インターフェイスに対応するClassオブジェクトを取得できますが、Classクラスは、Javaアプリケーションでクラスとインターフェイスを表すことを明示しています。ただし、インターフェイス自体は処理されません。クラスとして、したがって静的メソッドをアタッチすることはできません。
Java 1.8インターフェイスの静的メソッドは、インターフェイスメソッドにのみ表示されます。methodExamplesクラスからmethodSta1()メソッドを削除すると、InterfaceExampleオブジェクトに使用できなくなります。ただし、他の静的メソッドと同様に、クラス名を使用してインターフェイス静的メソッドを使用できます。たとえば、有効なステートメントは次のようになります。exp1.methodSta1();
以下の例を見て、次のように言うことができます:1)Java interface staticメソッドはインターフェイスの一部であり、実装クラスオブジェクトには使用できません。
2)Javaインターフェイスの静的メソッドは、nullチェック、コレクションのソート、ログなどのユーティリティメソッドを提供するのに適しています。
3)Javaインターフェース静的メソッドは、実装クラス(InterfaceExample)によるオーバーライドを許可しないことにより、セキュリティの提供に役立ちます。
4)オブジェクトクラスメソッドのインターフェイス静的メソッドを定義できません。「この静的メソッドはオブジェクトからインスタンスメソッドを隠すことはできません」としてコンパイラエラーが発生します。これは、Objectがすべてのクラスの基本クラスであり、同じシグネチャを持つ1つのクラスレベルの静的メソッドと別のインスタンスメソッドを作成できないため、Javaでは許可されないためです。
5)Javaインターフェイスの静的メソッドを使用して、コレクションなどのユーティリティクラスを削除し、そのすべての静的メソッドを対応するインターフェイスに移動できます。
public class InterfaceExample implements exp1 {
@Override
public void method() {
System.out.println("From method()");
}
public static void main(String[] args) {
new InterfaceExample().method2();
InterfaceExample.methodSta2(); // <--------------------------- would not compile
// methodSta1(); // <--------------------------- would not compile
exp1.methodSta1();
}
static void methodSta2() { // <-- it compile successfully but it can't be overridden in child classes
System.out.println("========= InterfaceExample :: from methodSta2() ======");
}
}
interface exp1 {
void method();
//protected void method1(); // <-- error
//private void method2(); // <-- error
//static void methodSta1(); // <-- error it require body in Java 1.8
static void methodSta1() { // <-- it compile successfully but it can't be overridden in child classes
System.out.println("========= exp1:: from methodSta1() ======");
}
static void methodSta2() { // <-- it compile successfully but it can't be overridden in child classes
System.out.println("========= exp1:: from methodSta2() ======");
}
default void method2() { System.out.println("--- exp1:: from method2() ---");}
//synchronized default void method3() { System.out.println("---");} // <-- Illegal modifier for the interface method method3; only public, abstract, default, static
// and strictfp are permitted
//final default void method3() { System.out.println("---");} // <-- error
}
インターフェイスでは静的な最終フィールドのみを宣言できます(「public」キーワードを含めなくてもパブリックであるメソッドと同様に、静的フィールドはキーワードの有無にかかわらず「最終」です)。
これらは単なる値であり、コンパイル時に使用される場所に文字通りコピーされるため、実行時に静的フィールドを実際に「呼び出す」ことはありません。静的メソッドは、セマンティクスが同じではありません。実装なしでインターフェイスを呼び出す必要があるため、Javaでは許可されません。
オブジェクトを作成せずに静的メソッドにアクセスでき、インターフェイスでは、プログラマが実装されたクラスからではなくインターフェイスメソッドを直接使用することを制限するため、オブジェクトの作成は許可されません。ただし、インターフェイスで静的メソッドを定義すると、実装せずに直接アクセスできます。したがって、静的メソッドはインターフェイスで許可されていません。一貫性が問題になるとは思わない。
その理由は、その修飾子を明示的に宣言するかどうかに関係なく、インターフェイスで定義されているすべてのメソッドは抽象的だからです。静的メソッドはオーバーライドできないため、抽象静的メソッドは修飾子の許容される組み合わせではありません。
インターフェースが静的フィールドを許可する理由について。私は「機能」と見なされるべきだと感じています。私が考えることができる唯一の可能性は、インターフェイスの実装が興味を持つ定数をグループ化することです。
一貫性がより良いアプローチであったことに同意します。インターフェイスで静的メンバーを許可しないでください。