インターフェース変数がデフォルトでJavaの静的で最終的なのはなぜですか?
インターフェース変数がデフォルトでJavaの静的で最終的なのはなぜですか?
回答:
Philip ShawによるJavaインターフェース設計FAQから:
Javaインターフェースはそれ自体ではインスタンス化できないため、インターフェース変数は静的です。変数の値は、インスタンスが存在しない静的コンテキストで割り当てる必要があります。最後の修飾子は、インターフェイス変数に割り当てられた値が、プログラムコードによって再割り当てできない真の定数であることを保証します。
static
修飾子のこの説明は完全に偽です。クラスのパブリックインスタンス変数はそのインターフェースの一部であり、interface
インスタンスメソッドのようにJava で抽象化されるべきではない理由はありません。Java interface
を直接インスタンス化できないことは問題ではありません。それでも、を実装するクラスのインスタンスを持つことができinterface
、特定のパブリックインスタンス変数があることを要求するのが賢明です。についての部分に関してはfinal
、それはまったく説明を提供しません-それは何がfinal
意味するのかを説明するだけです。
インターフェースには直接オブジェクトがないため、クラス/インターフェースを使用する方法しかありません。そのため、インターフェース変数が存在する場合は静的でなければならず、それ以外の場合は外部からまったくアクセスできません。これは静的なので、1つの値しか保持できず、それを実装するクラスはそれを変更できるため、すべて混乱します。
したがって、インターフェース変数があったとしても、それは暗黙的に静的で、最終的なものであり、明らかにパブリックです!!!
interface
。クラスはインターフェースを実装し、インスタンス変数を宣言します(インターフェースの必要に応じて)。そのコンストラクター(または他のメソッド)がインスタンス変数を設定します。クラスのインスタンスがインスタンス化されると、そのインスタンス変数にアクセスできるようになります。
public:インターフェースに存在するメソッドと同様に、すべてのクラスにわたるアクセシビリティのため
static:インターフェースはオブジェクトを持つことができないため、interfaceName.variableNameを使用してそれを参照したり、それを実装するクラスのvariableNameを直接使用したりできます。
final:それらを定数にする。2つのクラスが同じインターフェースを実装し、両方に値を変更する権利を与えると、varの現在の値で競合が発生するため、初期化は1回しか許可されません。
また、これらの修飾子はすべてインターフェースに対して暗黙的であり、実際にそれらを指定する必要はありません。
(これは哲学的な答えではなく、実際的な答えです)。static
修飾子の要件は明白であり、他の人から回答されています。基本的に、インターフェースはインスタンス化できないため、そのフィールドにアクセスする唯一の方法は、それらをクラスフィールドにすることです-static
。
interface
フィールドが自動的にfinal
(定数)になる理由は、別の実装が誤って他の実装の動作に影響を与える可能性があるインターフェース変数の値を変更するのを防ぐためです。interface
プロパティがfinal
Javaによって明示的になされなかった以下のシナリオを想像してください。
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
別のクラスによって影響を受ける可能性があります。CleanAction
performAction()
CleanAction
実行(同じスレッドで)可能性があります。 (意味的にはそうです)。
の各実装がinterface
これらの変数をどのように使用するかはわからないため、暗黙的にでなければなりませんfinal
。
他のものは実装の一部であり、インターフェースは実装を含むことができないからです。
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つだと思います。
インターフェイス内で変数を宣言しないでください。
static final
、実際には静的で最終的な変数の前に書かれているのを見たことがないかもしれません。
static-インターフェイスはインスタンスを持つことができないため。そして最後-変更する必要がないため。
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
}
後で他のインターフェイスと一緒に実装したくない場合は、インターフェイスなしの抽象クラスを使用することもできます。抽象クラスのインスタンスを作成することはできません。最初に拡張する必要があります。
(「保護された」キーワードは、拡張クラスだけがこれらのメソッドと変数にアクセスできることを意味します。)
スパイロ
インターフェイス:システム要件サービス。
インターフェイスでは、変数はデフォルトでpublic、static、finalアクセス修飾子によって割り当てられます。なぜなら:
public:インターフェースが他のパッケージに配置される場合があります。したがって、プロジェクトのどこからでも変数にアクセスする必要があります。
static:そのような不完全なクラスはオブジェクトを作成できません。プロジェクトでは、オブジェクトなしで変数にアクセスする必要があるので、interface_filename.variable_name
final: 1つのインターフェースが多くのクラスによって実装されており、すべてのクラスがインターフェース変数にアクセスして更新しようとしているとします。そのため、データの変更に一貫性がなくなり、他のすべてのクラスに影響します。したがって、finalでアクセス修飾子を宣言する必要があります。
ではJava
、インターフェイスではインスタンス変数を宣言できません。インターフェイスで宣言された変数をインスタンス変数として使用すると、コンパイル時エラーが返されます。
static final
インスタンス変数とは異なる定数変数を宣言できます。
インターフェイスは任意のクラスで実装でき、その値が実装クラスの1つによって変更された場合、他の実装クラスに誤解を招く可能性があります。インターフェイスは基本的に、2つの相互に関連しているが異なるエンティティを組み合わせるための参照です。そのため、インターフェイスをインスタンス化できないため、インターフェイス内の宣言変数は暗黙的に最終的であり、静的でもあります。
Eclipseで試したところ、インターフェースの変数はデフォルトでfinalになっているため、変更できません。親クラスと比較して、変数は確実に変更可能です。どうして?ちなみに、クラスの変数は子に継承される属性で、実際の必要に応じて変更することができます。逆に、インターフェイスは属性ではなく動作のみを定義します。変数をインターフェースに入れる唯一の理由は、それらをそのインターフェースに関連する定数として使用することです。ただし、次の抜粋によると、これは良い方法ではありません。
「インターフェイスに定数を配置することは、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));
}
}