Javaがインターフェイスでプライベートメンバーを許可しないのはなぜですか?特別な理由はありますか?
Javaがインターフェイスでプライベートメンバーを許可しないのはなぜですか?特別な理由はありますか?
回答:
「Javaプログラミング言語は、パッケージまたはクラスのユーザーがそのパッケージまたはクラスの実装の不要な詳細に依存するのを防ぐために、アクセス制御のメカニズムを提供します。」
アクセス制御とは、実装の詳細を隠すことです。インターフェイスには非表示にする実装がありません。
Java 9では、インターフェイスでプライベートメソッドを使用できます。
javacコンパイラチームは、JDKの9b54ビルド以降のインターフェイスでプライベートメソッドのコンパイラサポートが利用可能になったことをお知らせします。
プライベートインターフェイスメソッドは、JEP-213の一部としてJava9の一部です。Java 8のインターフェースはデフォルトのメソッドを持つことができるため、プライベート・メソッドでは、複数のデフォルトのメソッドが共有プライベート・メソッドを使用できます。
Java 8以降、インターフェースはデフォルトのメソッドを持つことができ、Java 9以降、インターフェースは、同じインターフェース内のデフォルトのメソッドによってのみアクセスできるプライベートメソッドを持つことができます。
そのようなインターフェースを実装する方法はありません。 私が提起した質問への回答は、プライベートメソッドでインターフェイスを実装することは(ルールを根本的に変更せずに)不可能であることを強く示唆しています-これは、保護されたプライベートメソッドとパッケージプライベートメソッドが許可されない理由の疑問を残します。
class OuterClass
{
void run ( MyInterface x )
{
x . publicMethod ( ) ; // why not?
x . protectedMethod ( ) ; // why not?
x . packagePrivateMethod ( ) ; // why not?
x . privateMethod ( ) ; // why not?
}
interface MyInterface
{
public abstract void publicMethod ( ) ; // OK
protected abstract void protectedMethod ( ) ; // why not?
abstract void packagePrivateMethod ( ) ; // in interface default is public, but why not package private
private void privateMethod ( ) ; // impossible to implement
}
class MyImpl implements MyInterface
{
public void publicMethod ( ) { } // ok
protected void protectedMethod ( ) { } // no sweat
void packagePrivateMethod ( ) { } // no sweat
private void privateMethod ( ) { } // not happening
}
}
以下のコードは、望ましい結果を達成するはずです。すべてのメソッドがパブリックですが、事実上パブリックであるのはパブリックメソッドのみです。保護されたメソッドは効果的に保護されます。packagePrivateMethodは事実上packagePrivateです。privateMethodは事実上プライベートです。
class WorkAround
{
void run ( MyPrivateInterface x )
{
x . publicMethod ( ) ;
x . protectedMethod ( ) ;
x . packagePrivateMethod ( ) ;
x . privateMethod ( ) ;
}
public interface MyPublicInterface { void publicMethod ( ) ; }
protected interface MyProtectedInterface extends MyPublicInterface { void protectedMethod ( ) ; }
interface MyPackagePrivateInterface extends MyProtectedInterface { void packagePrivateMethod ( ) ; }
private interface MyPrivateInterface extends MyPackagePrivateInterface { void privateMethod ( ) ; }
}
Javaでは、Java9のインターフェイスでプライベートメソッドを使用できます。デフォルトの方法は、複数のデフォルトの方法はいくつかのコードを共有したいことがあるのJava 8で導入された場合、このコードは、外の世界にそれをさらすことなく、プライベートメソッドに移動することができます。このバグは修正され、JDK 9ビルド54から、プライベートインターフェイスメソッドのコンパイラサポートが復活しました。
public interface IData{
default void processData(int data) {
validate(data);
// do some work with it
}
default void consumeData(int data) {
validate(data);
// do some work with it
}
private void validate(int data) {
// validate data
}
}
役に立たないからです。
プライベートメソッドを呼び出す方法はありません。
プライベートメンバーは実装の詳細です。インターフェースは、クラスが引き受けることができるパブリックロールに関するものです。
プライベートフィールドは、他のフィールドや内部クラスがアクセスできるため、完全に役に立たないわけではありません。
ただし、ネストされたクラスであってもプライベートメソッドを実装できなかったため、ほとんど役に立たなくなりました。リフレクションを使用してそれらを読むことができますが、それはむしろエッジケースです。
うん、それはできません。なぜそうすべきでないのかについてコメントしているすべての人のために:
インターフェイスIを利用するクラスAがあるとします。クラスBはクラスAを拡張するため、Aのすべてのインターフェイスメソッドも継承します。
ここで、クラスAにプライベートメソッドが必要であるが、他のクラス(クラスBまたはAを必ずしも拡張しないクラスC)に対しても契約上定義する必要があると想像してください。
おそらく「初期化」メソッドの場合、Iインターフェイスを使用するすべてのクラスに必要です。しかし、明らかに私は初期化メソッドをパブリックにしたくありません....一度だけ使用するか、クラスが必要と見なすときに使用する必要があるため、すべてを意地悪に使用したいという理由だけではありません。
唯一の解決策は、回避策、またはインターフェイスなしでinitメソッドをクラス自体に強制することです。
その理由も確かにわかりますが、それでも役立つ場合があります。明らかに、OracleはJDK9でプライベートインターフェイスメソッドを許可していることに同意しています。
とにかく私がしたことは、単純なブール変数を配置することでした。これにより、一度設定した後、インターフェイスメソッド(プライベートである必要があります)にtrue(初期化= true)のフラグを付けることができます。その後、再度呼び出された場合、メソッドは単に何もしません。このようにして、インターフェイスメソッドをパブリックとして実装できますが、(私のクラスの)コンストラクターが最初にメソッドを呼び出すため、変数がtrueに設定され、再度呼び出すことはできません。
それ以外の場合、クラスの内部動作のみで使用する場合は、別の回避策を試す必要があります。おそらく、メソッド自体が使用時にフラグをオンまたはオフに設定します。フラグがfalseの場合、メソッドは何もしません(これは、誰かがクラスの外部からフラグを呼び出す場合です)。ただし、クラス独自のメソッドがそれを呼び出すと、すぐにフラグをtrueに設定し、次にメソッドを呼び出し、次にフラグをfalseに設定しますか?
結局のところ、ミュートのようなものです。おそらく今のところ、プライベートクラスをクラス自体に配置し、インターフェイスを完全に切り取る方がよいでしょう。