なぜJavaはインターフェースでプライベートメンバーを許可しないのですか?特別な理由はありますか?
13 に答える
Java言語仕様から、(アクセス制御) :
「Javaプログラミング言語は、パッケージまたはクラスのユーザーがそのパッケージまたはクラスの実装の不要な詳細に依存することを防ぐために、アクセス制御のメカニズムを提供します。」
アクセス制御とは、実装の詳細を隠すことです。インターフェイスには非表示にする実装がありません。
プライベート インターフェイス メソッドは、 JEP-213の一部として Java 9 の一部です。Java 8 のインターフェースはデフォルト メソッドを持つことができるため、プライベート メソッドを使用すると、複数のデフォルト メソッドで共有プライベート メソッドを使用できます。
インターフェイスは、インターフェイスを実装するクラスによって提供されるAPIを記述するために使用されます。その定義からのインターフェースには状態がないため、フィールドメンバーを宣言することはできません。
そのようなインターフェースを実装する方法はありません。 私が提起した質問への回答は、プライベート メソッドを使用してインターフェイスを実装することは (ルールを根本的に変更しない限り) 不可能であることを強く示唆しています。
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
のプログラミング言語によると、 のスコープは、宣言されている にprivate members
限定されておりclass
、その のメソッドによってのみアクセスできますclass
。ただしinteface
、メソッド本体がないため、 内でプライベート メンバーを宣言する必要はありませんinterface
。
役に立たないからです。
プライベートメソッドを呼び出す方法はありません。
プライベートメンバーは実装の詳細です。インターフェースは、クラスが引き受けることができるパブリックな役割に関するものです。
プライベートフィールドは、他のフィールドや内部クラスがそれらにアクセスできるため、完全に役に立たないわけではありません。
ただし、ネストされたクラスであってもプライベートメソッドを実装できなかったため、ほとんど役に立たなくなりました。リフレクションを使用してそれらを読むことができますが、それはむしろエッジケースです。
プライベートメンバーは、インターフェイスでは意味がありません。インターフェイスは、定義されたメソッドを使用してクラスにアクセスする方法であり、そのクラスの内部を確認する必要はありません。
個人会員はそれに同意しません。
private と宣言されたクラスのメンバーは、そのクラスのサブクラスに継承されません。クラスが宣言されているパッケージ以外のパッケージで宣言されているサブクラスによって継承されるのは、protected または public と宣言されているクラスのメンバーのみです。
ソース
だから、そのプライベートな継承不可能なフィールドを操作できるインターフェイスには、機能するメソッドがありません。では、なぜそれが存在する必要があるのでしょうか?
ええ、それはできません。なぜそうすべきではないのかについてコメントしているすべての人のために:
インターフェイス I を利用するクラス A があるとします。クラス B はクラス A を拡張するため、A のすべてのインターフェイス メソッドも継承します。
ここで、クラス A にプライベート メソッドが必要であるが、それを他のクラス (クラス B または A を必ずしも拡張しないクラス C) に対しても契約上定義したいとします。
おそらく、I インターフェイスを使用するすべてのクラスに必要な「初期化」メソッドの場合です。しかし、明らかに、初期化メソッドをパブリックにしたくありません....一度だけ使用するか、クラスが必要と判断した場合にのみ使用する必要があるためです。
唯一の解決策は、回避策、またはインターフェイスを使用せずに単に init メソッドをクラス自体に強制することです。
確かにその理由はよくわかりませんが、それでも時々役立つことがあります。Oracle は明らかに、JDK 9 でプライベート インターフェイス メソッドを許可していることに同意しています。
とにかく、私がしたことは、単純なブール変数を配置することでした。これにより、インターフェースメソッド(プライベートである必要があります)が一度設定された後にtrue(initialized = true)としてフラグを立てることができます。その後、再度呼び出されると、メソッドは何もしません。このようにして、インターフェイス メソッドを public として実装できますが、(私のクラスの) コンストラクターが最初にメソッドを呼び出すため、変数が true に設定されるため、再度呼び出すことはできません。
それ以外の場合は、クラスの内部動作のみを使用する場合は、別の回避策を試す必要があります....おそらく、メソッド自体がフラグを使用するときにオンとオフを設定します。フラグが false の場合、メソッドは何もしません (これは、誰かがクラスの外から呼び出した場合です)。ただし、クラス独自のメソッドがそれを呼び出すと、すぐにフラグを true に設定し、メソッドを呼び出してから、フラグを false に設定しますか??
最後に一種のミュート。おそらく今のところは、単純にプライベート クラスをクラス自体に配置し、インターフェイスを完全に切り取ったほうがよいでしょう。