Javaでは、インタフェース変数がデフォルトで静的かつ最終的なのはなぜですか?
Philip ShawによるJavaインターフェース設計FAQから:
Javaインタフェースはそれ自体ではインスタンス化できないため、インタフェース変数は静的です。変数の値は、インスタンスが存在しない静的コンテキストで割り当てる必要があります。最後の修飾子は、インターフェイス変数に割り当てられた値が、プログラムコードによって再割り当てできない真の定数であることを確認します。
インターフェースは直接のオブジェクトを持っていないので、それらにアクセスする唯一の方法はクラス/インターフェースを使用することであり、それ故インターフェース変数が存在するならそれは静的であるべきですこれは静的なので、1つの値しか保持できず、それを実装するクラスはすべて変更できます。したがって、すべて混乱します。
したがって、インターフェース変数があるとすれば、それは暗黙的に静的、最終的、そして明らかにpublicになるでしょう。
public:インタフェースに存在するメソッドと同じように、すべてのクラスにわたるアクセシビリティのために
static:interfaceはオブジェクトを持つことができないため、interfaceName.variableNameを使用してそれを参照するか、それを実装するクラス内のvariableNameを直接使用できます。
final:それらを定数にします。 2つのクラスが同じインタフェースを実装していて、両方に値を変更する権利を与えた場合、varの現在の値で競合が発生するため、初期化は1回しか許可されません。
また、これらの修飾子はすべてインターフェースに対して暗黙的なものであり、実際にこれらのいずれかを指定する必要はありません。
(これは哲学的な答えではなく、より実用的なものです)。 static
修飾子の要件は明らかで、他の人によって答えられました。基本的に、インタフェースはインスタンス化できないので、そのフィールドにアクセスする唯一の方法はそれらをクラスフィールドにすることです - static
。
interface
フィールドが自動的にfinal
(定数)になるのは、誤って他の実装の動作に影響を与える可能性があるインタフェース変数の値が異なる実装によって誤って変更されるのを防ぐためです。以下のシナリオで、interface
プロパティが明示的にJavaによってfinal
にならなかったとします。
public interface Actionable {
public static boolean isActionable = false;
public void performAction();
}
public NuclearAction implements Actionable {
public void performAction() {
// Code that depends on isActionable variable
if (isActionable) {
// Launch nuclear weapon!!!
}
}
}
さて、Actionable
を実装する別のクラスがインターフェース変数の状態を変更するとどうなるか考えてみてください。
public CleanAction implements Actionable {
public void performAction() {
// Code that can alter isActionable state since it is not constant
isActionable = true;
}
}
これらのクラスがクラスローダによって単一のJVM内にロードされると、NuclearAction
の実行後にそのperformAction()
が呼び出されると、CleanAction
の動作が別のクラスCleanAction
の影響を受ける可能性があります。悲惨なこと(意味的には).
interface
の各実装がこれらの変数をどのように使用するのかわからないので、それらは暗黙のうちにfinal
でなければなりません。
それ以外は実装の一部であり、インターフェイスには実装を含めることができないためです。
static - インタフェースはインスタンスを持てないためそして最後に - 変更する必要がないからです。
public interface A{
int x=65;
}
public interface B{
int x=66;
}
public class D implements A,B {
public static void main(String[] a){
System.out.println(x); // which x?
}
}
これが解決策です。
System.out.println(A.x); // done
それが、インターフェース変数が静的な理由の1つだと思います。
Interface内で変数を宣言しないでください
なぜなら
Static
:インターフェイスのオブジェクトを持つことはできないので、オブジェクトレベルのメンバ変数の使用は避け、クラスレベルの変数、つまりstaticを使用してください。
Final
:変数の値があいまいにならないようにします(Diamond problem - Multiple Inheritance)。
そしてドキュメンテーションインターフェースは契約であり、実装ではありません。
参考:Abhishek Jainのquoraに対する回答 http://qr.ae/TU1dTm
Javaでは、インタフェースで抽象変数やコンストラクタの定義を許可していません。解決策:インタフェースと実装の間に抽象クラスをハングさせるだけで、抽象クラスは次のように拡張されるだけです。
public interface IMyClass {
void methodA();
String methodB();
Integer methodC();
}
public abstract class myAbstractClass implements IMyClass {
protected String varA, varB;
//Constructor
myAbstractClass(String varA, String varB) {
this.varA = varA;
this.varB = VarB;
}
//Implement (some) interface methods here or leave them for the concrete class
protected void methodA() {
//Do something
}
//Add additional methods here which must be implemented in the concrete class
protected abstract Long methodD();
//Write some completely new methods which can be used by all subclasses
protected Float methodE() {
return 42.0;
}
}
public class myConcreteClass extends myAbstractClass {
//Constructor must now be implemented!
myClass(String varA, String varB) {
super(varA, varB);
}
//All non-private variables from the abstract class are available here
//All methods not implemented in the abstract class must be implemented here
}
あとで他のインターフェースと一緒に実装したくない場合は、抽象クラス without anyインターフェースを使用することもできます。抽象クラスのインスタンスを作成することはできません。最初にそれを拡張する必要があります。
( "protected"キーワードは、拡張クラスだけがこれらのメソッドと変数にアクセスできることを意味します。)
スピロ
インターフェースは、不変で、石に刻まれた、したがって最終的な2者間の契約です。 契約による設計 を参照してください。
インターフェースが定義されていて他のクラスがそれを実装しているWebアプリケーションを考えてください。変数にアクセスするためのinterfaceのインスタンスを作成することはできませんので、staticキーワードが必要です。静的なので、値の変更はそれを実装した他のインスタンスに反映されます。それを防ぐために、それらを最終的なものとして定義します。
Eclipseで試したところ、interfaceの変数はデフォルトでfinalになっているので変更できません。親クラスと比べて、変数は確実に変更可能です。どうして?私の考えでは、クラス内の変数は子供に継承される属性であり、子供は実際の必要に応じてそれを変更することができます。それどころか、インターフェースは振る舞いを定義するだけで属性は定義しません。インターフェイスに変数を入れる唯一の理由は、それらをそのインターフェイスに関連するconstとして使用することです。ただし、以下の抜粋によると、これは良い習慣ではありません。
「インターフェースに定数を配置することは、Javaの初期の頃は一般的な手法でしたが、インターフェースではデータではなくオブジェクトによって提供されるサービスを処理する必要があるため、現在ではインターフェースの使い方が不愉快になっています。クラスによって、通常は実装の詳細ですが、それらをインタフェースに配置すると、それらはクラスのパブリックAPIに昇格します。」
私はまた静的に置くか、まったく違いがないかを試してみました。コードは以下のとおりです。
public interface Addable {
static int count = 6;
public int add(int i);
}
public class Impl implements Addable {
@Override
public int add(int i) {
return i+count;
}
}
public class Test {
public static void main(String... args) {
Impl impl = new Impl();
System.out.println(impl.add(4));
}
}
Java
では、インターフェイスではインスタンス変数を宣言できません。インスタンス変数としてインターフェイスで宣言された変数を使用すると、コンパイル時エラーが返されます。
インスタンス変数とは異なるstatic final
を使用して、定数変数を宣言できます。
インターフェースはどのクラスでも実装できますが、その値がその実装クラスの1つによって変更された場合、他の実装クラスには誤解が生じます。そのため、インターフェースはインスタンス化できないため、インターフェース内の宣言変数は暗黙的に最終的で、静的にもなります。