回答:
はい、Javaインターフェース内にネストされたクラスと内部クラスの両方を作成できます(一般的に、「静的内部クラス」などは存在しないと信じています。これは単に意味がなく、「内部」も「も」はありません。入れ子になったクラスが静的である場合、「外部」クラスであるため、「静的内部」にすることはできません。
とにかく、次のコードは問題なくコンパイルされます。
public interface A {
class B {
}
}
ある種の「契約チェッカー」をインターフェース定義に直接配置するために使用されたのを見てきました(まあ、インターフェースにネストされたクラスでは、静的メソッドを持つことができ、逆にインターフェース自体にはできません)。正しく思い出せばこんな感じ。
public interface A {
static class B {
public static boolean verifyState( A a ) {
return (true if object implementing class A looks to be in a valid state)
}
}
}
私はそのようなことの有用性についてコメントしているのではなく、単にあなたの質問に答えているだけであることに注意してください。それは可能であり、これは私が見たことのある用途の1つです。
今、私はそのような構成の有用性についてコメントしません、そして私が見たからです:私はそれを見ましたが、それは非常に一般的な構成ではありません。
これが正確にゼロタイムで発生するここ200KLOCコードベース(ただし、他の人が完全に正常であると感じるほど正確にゼロタイムで発生する悪い慣行を考慮する他の多くの事柄があります...)。
interface
ことができません。のネストされたクラスのstatic
修飾子は省略できますがinterface
、それでもネストされたクラスであり、内部クラスではありません。
B
クラスは静的なネストされたクラスであり、内部クラスではありません。インターフェイスは特別な扱いを受けます。仕様自体を除いて、オンラインでの言及は見つかりませんでした。「インターフェイスのメンバークラスは暗黙的に静的であるため、内部クラスとは見なされません。」docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
はい、インターフェイス内にクラスを含めることができます。使用法の一例は
public interface Input
{
public static class KeyEvent {
public static final int KEY_DOWN = 0;
public static final int KEY_UP = 1;
public int type;
public int keyCode;
public char keyChar;
}
public static class TouchEvent {
public static final int TOUCH_DOWN = 0;
public static final int TOUCH_UP = 1;
public static final int TOUCH_DRAGGED = 2;
public int type;
public int x, y;
public int pointer;
}
public boolean isKeyPressed(int keyCode);
public boolean isTouchDown(int pointer);
public int getTouchX(int pointer);
public int getTouchY(int pointer);
public float getAccelX();
public float getAccelY();
public float getAccelZ();
public List<KeyEvent> getKeyEvents();
public List<TouchEvent> getTouchEvents();
}
ここで、コードには2つのネストされたクラスがあり、後でgetKeyEvents()などのメソッド定義で使用されるイベントオブジェクトに関する情報をカプセル化します。それらを入力インターフェース内に配置すると、まとまりが向上します。
有効な使用法であるIMHOは、囲んでいるインターフェースメソッドによって受信または返されるオブジェクトの定義です。通常、データ保持構造。このようにして、オブジェクトがそのインターフェースにのみ使用される場合、よりまとまりのある方法で物事ができます。
例として:
interface UserChecker {
Ticket validateUser(Credentials credentials);
class Credentials {
// user and password
}
class Ticket {
// some obscure implementation
}
}
とにかく...それは好みの問題だけです。
興味深いユースケースは、https://stackoverflow.com/a/3442218/454667(単一クラスの継承の問題を克服するため)に説明されているように、内部クラスを介してメソッドをインターフェースするための一種のデフォルト実装を提供することです。
それは確かに可能であり、私がそれが有用であるとわかった1つのケースは、インターフェイスがカスタム例外をスローする必要がある場合です。例外を関連付けられたインターフェースで保持します。これは、ソースツリーを単純な例外ファイルのヒープで散らかすよりも多くの場合、私はよく考えられていると思います。
interface MyInterface {
public static class MyInterfaceException extends Exception {
}
void doSomething() throws MyInterfaceException;
}
はい、インターフェイス内に静的クラス定義を含めることは可能ですが、この機能の最も有用な側面は、列挙型(特別な種類の静的クラス)を使用する場合でしょう。たとえば、次のようにすることができます。
public interface User {
public enum Role {
ADMIN("administrator"),
EDITOR("editor"),
VANILLA("regular user");
private String description;
private Role(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
public String getName();
public void setName(String name);
public Role getRole();
public void setRole(Role role);
...
}
@Bachiが言及していることはScalaの特性に似ており、実際にはインターフェース内のネストされたクラスを使用して実装されます。これはJavaでシミュレートできます。Javaトレイトまたはミックスインパターンも参照してください。
おそらく、いくつかの異なる実装動作のようなより複雑な構成が必要な場合は、次のことを考慮してください。
public interface A {
public void foo();
public static class B implements A {
@Override
public void foo() {
System.out.println("B foo");
}
}
}
これはあなたのインターフェースであり、これは実装者になります:
public class C implements A {
@Override
public void foo() {
A.B b = new A.B();
b.foo();
}
public static void main(String[] strings) {
C c = new C();
c.foo();
}
}
いくつかの静的実装を提供する可能性がありますが、混乱しないでしょう、私にはわかりません。