インターフェイスで定義されたすべてのフィールドが暗黙的にである理由を理解しようとしていstatic
ますfinal
。インターフェイスのオブジェクトを持つことはできないので、フィールドを保持するという考えはstatic
私には理にかなっていますが、なぜそれらはfinal
(暗黙的に)あるのですか?
static
Java設計者がインターフェイスでフィールドを作成することになった理由を誰もが知っていますfinal
か?
インターフェイスで定義されたすべてのフィールドが暗黙的にである理由を理解しようとしていstatic
ますfinal
。インターフェイスのオブジェクトを持つことはできないので、フィールドを保持するという考えはstatic
私には理にかなっていますが、なぜそれらはfinal
(暗黙的に)あるのですか?
static
Java設計者がインターフェイスでフィールドを作成することになった理由を誰もが知っていますfinal
か?
インターフェイスは、実装の詳細ではなく、対話コントラクトを指定することを目的としています。開発者は、インターフェースを見るだけで実装を使用でき、それを実装するクラスの内部を調べる必要はありません。
コンストラクターを指定できないため、インターフェースではインスタンスを作成できません。したがって、インスタンスの状態を持つことはできませんが、インターフェイスフィールドは、暗黙的に静的で最終的な定数を定義できます。
インターフェイスでメソッド本体または初期化子ブロックを指定することはできませんが、Java 8以降、本体を使用してデフォルトのメソッドを指定できます。この機能は、すべての実装を更新することなく、既存のインターフェースに新しいメソッドを追加できるようにすることを目的としています。ただし、最初にインターフェイスを実装するインスタンスを作成しない限り、このようなメソッドを実行することはできません。
余談ですが、匿名の内部クラスを使用してインターフェースを実装できることに注意してください。
interface Foo {
String bar();
}
class FooBar {
Foo anonymous = new Foo() {
public String bar() {
return "The Laundromat Café";
};
}
匿名内部クラスがコンパイルするためのインターフェースの完全な実装を提供する必要があります。
new Foo()
は、デフォルトのコンストラクターを使用して匿名内部クラスを初期化しています。
である理由final
フィールドがfinalとして定義されていない場合、どの実装でもフィールドの値を変更できます。その後、それらは実装の一部になります。インターフェイスは、実装のない純粋な仕様です。
である理由static
それらが静的である場合、それらはインターフェースに属し、オブジェクトにも、オブジェクトの実行時型にも属しません。
ここにはいくつかのポイントがあります。
インターフェイスのフィールドが暗黙的に静的finalであるからといって、それらがコンパイル時定数である必要がある、または不変である必要があるという意味ではありません。あなたは例えばを定義することができます
interface I { String TOKEN = SomeOtherClass.heavyComputation(); JButton BAD_IDEA = new JButton("hello"); }
(アノテーション定義内でこれを行うと、上記が実際に静的初期化子にコンパイルされるという事実に関連して、javacを混乱させる可能性があることに注意してください。)
また、この制限の理由は技術的というよりも文体的であり、多くの人々はそれがリラックスすることを望んでいます。
フィールドは抽象化できないため(メソッドのように)、静的である必要があります。それらは抽象化できないため、実装者はフィールドのさまざまな実装を論理的に提供することはできません。
フィールドは最終的なものでなければならない、と私は思う。なぜなら、フィールドは多くの異なる実装者によってアクセスされる可能性があるため、変更可能にすることは(同期として)問題になる可能性があるからだ。また、再実装(非表示)されないようにするためです。
ただ私の考え。
私は、フィールドが最終的なものであるという要件は、Java言語設計者による過度に制限的で間違いであると考えています。インターフェースタイプのオブジェクトで操作を実行するために必要な定数を実装で設定する必要がある場合、たとえばツリー処理があります。実装クラスでコードパスを選択するのは簡単ではありません。私が使用する回避策は、インターフェイス関数を定義し、リテラルを返すことによってそれを実装することです。
public interface iMine {
String __ImplementationConstant();
...
}
public class AClass implements iMine {
public String __ImplementationConstant(){
return "AClass value for the Implementation Constant";
}
...
}
public class BClass implements iMine {
public String __ImplementationConstant(){
return "BClass value for the Implementation Constant";
}
...
}
ただし、次の構文を使用すると、実装がより単純で明確になり、異常な実装が発生しにくくなります。
public interface iMine {
String __ImplementationConstant;
...
}
public class AClass implements iMine {
public static String __ImplementationConstant =
"AClass value for the Implementation Constant";
...
}
public class BClass implements iMine {
public static String __ImplementationConstant =
"BClass value for the Implementation Constant";
...
}
仕様、契約...フィールドアクセスの機械命令は、オブジェクトアドレスとフィールドオフセットを使用します。クラスは多くのインターフェイスを実装できるため、このインターフェイスを拡張するすべてのクラスで非最終インターフェイスフィールドに同じオフセットを持たせる方法はありません。したがって、フィールドアクセスの異なるメカニズムを実装する必要があります。1つではなく2つのメモリアクセス(フィールドオフセットの取得、フィールド値の取得)に加えて、仮想フィールドテーブル(仮想メソッドテーブルのアナログ)の種類を維持します。既存のもの(メソッド)を介して簡単にシミュレートできる機能のためにjvmを複雑にしたくなかったと思います。
Scalaでは、インターフェースにフィールドを含めることができますが、内部的には上記で説明したように(メソッドとして)実装されます。
static
:
Javaにあるもの(変数またはメソッド)はすべて、または直接static
呼び出すことができます。オブジェクト名のみを使用して呼び出す必要はありません。Classname.variablename
Classname.methodname
インターフェイスでは、オブジェクトを宣言static
することはできず、オブジェクト名を必要とせずにクラス名だけで変数を呼び出すことができます。
final
:
サブクラスでオーバーライドできないため、変数の定数値を維持するのに役立ちます。