Javaがインターフェイスでプライベートメンバーを許可しないのはなぜですか?


87

Javaがインターフェイスでプライベートメンバーを許可しないのはなぜですか?特別な理由はありますか?


- @pst私は私の答えの最後に回避策を書いたstackoverflow.com/a/10169894/348975。それはあなたの懸念に対処していますか?
エモリー2012

Java9以降は許可されています。:下記の私の答えをチェックstackoverflow.com/questions/10169654/...
akhil_mittal

回答:


87

Java言語仕様、(アクセスコントロール)

「Javaプログラミング言語は、パッケージまたはクラスのユーザーがそのパッケージまたはクラスの実装の不要な詳細に依存するのを防ぐために、アクセス制御のメカニズムを提供します。」

アクセス制御とは、実装の詳細を隠すことです。インターフェイスには非表示にする実装がありません。


9
ネストクラスをインターフェイス内に配置できるため、実装をインターフェイスに配置できます。そうすることは非常に間違っていますが、私たちはできます。
エモリー2012

29
Java 9では、インターフェイスでプライベートメソッドを使用できます。デフォルトのメソッドを追加した後は論理的です。参照: bugs.openjdk.java.net/browse/JDK-8071453
Hariharan

3
「そうすることは非常に間違っています」..いつものように、文脈に依存します。
jacksOnF1re 2017

5
思ったほど悪くはありません。インターフェイスのプライベートメソッドには、同じインターフェイスのデフォルトのメソッドでのみアクセスできます。利点の1つは、カプセル化を壊すことなく、デフォルトのメソッドの実装を意味のある小さな関数に分割できるようにすることです。
ヘンリーファム2017

48

Java 9では、インターフェイスでプライベートメソッドを使用できます。

Java9の仕様

javacコンパイラチームは、JDKの9b54ビルド以降のインターフェイスでプライベートメソッドのコンパイラサポートが利用可能になったことをお知らせします。


10
@ SebiSebi、Javaがライブ言語であることに気付いた瞬間。
Arashsoft 2017

@ Arashsoft、OPはフィールドを要求しています。
ペースリエ

19

プライベートインターフェイスメソッドは、JEP-213の一部としてJava9の一部です。Java 8のインターフェースはデフォルトのメソッドを持つことができるため、プライベート・メソッドでは、複数のデフォルトのメソッドが共有プライベート・メソッドを使用できます。


13

Java 8以降、インターフェースはデフォルトのメソッドを持つことができ、Java 9以降、インターフェースは、同じインターフェース内のデフォルトのメソッドによってのみアクセスできるプライベートメソッドを持つことができます。


Java-9インターフェース機能について知っておくとよいでしょう。
ラビンドラバブ2017年

9

インターフェイスは、インターフェイスを実装するクラスによって提供されるAPIを記述するために使用されます。その定義からのインターフェースには状態がないため、フィールドメンバーを宣言することはできません。


Javaランドでは、メンバーはフィールド、メソッド、コンストラクター、またはクラスです。
エモリー2012

7

そのようなインターフェースを実装する方法はありません。 私が提起した質問への回答は、プライベートメソッドでインターフェイスを実装することは(ルールを根本的に変更せずに)不可能であること強く示唆しています-これは、保護されたプライベートメソッドとパッケージプライベートメソッドが許可されない理由の疑問を残します。

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 ( ) ; }
}

6

Javaプログラミング言語によると、のスコープは宣言private membersされているclassに限定されており、そのメソッドによってのみアクセスできますclass。ただしinteface、メソッド本体がないため、内でプライベートメンバーを宣言する必要はありませんinterface


4

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
   }
}

3

役に立たないからです。

プライベートメソッドを呼び出す方法はありません。

プライベートメンバーは実装の詳細です。インターフェースは、クラスが引き受けることができるパブリックロールに関するものです。


「プライベートメソッドを呼び出す方法はないだろう」と私は同意しません。内部クラスを使用すると、方法があります-stackoverflow.com/a/10169894/348975
emory 2012

Java 8のデフォルトのメソッドを検討してください。インターフェースIには、多くの一般的なコードを持つデフォルトのメソッドAとBがあります。これをリファクタリングするには、共有コードのみを含み、AとBによって呼び出されるメソッドCが必要です。Java8では、これはすべてのインターフェイス実装者に公開されるデフォルトのメソッドになります。ジャワ9 CでのみI.内のデフォルトメソッドに見えるプライベート方法かもしれない
イワンクリロフ

2

プライベートフィールドは、他のフィールドや内部クラスがアクセスできるため、完全に役に立たないわけではありません。

ただし、ネストされたクラスであってもプライベートメソッドを実装できなかったため、ほとんど役に立たなくなりました。リフレクションを使用してそれらを読むことができますが、それはむしろエッジケースです。


ここで重大な調査を行って申し訳ありません:(この場合、docs.oracle.com / javase / 7 / docs / api / java / io / Serializable.htmlはどのように機能しますか?実装してからreadObjectメソッドとwriteObjectメソッドを上書きすることはできません?何かが足りないと確信しています
PatrickWalker

1

プライベートメンバーは、インターフェイスでは意味がありません。インターフェイスは、定義されたメソッドを使用してクラスにアクセスする方法であり、そのクラスの内部を確認する必要はありません。

個人会員はそれに同意しません。


0

プライベートとして宣言されたクラスのメンバーは、そのクラスのサブクラスに継承されません。保護またはパブリックと宣言されたクラスのメンバーのみが、クラスが宣言されたパッケージ以外のパッケージで宣言されたサブクラスによって継承されます。

ソース

それで、あなたはそのプライベートな継承不可能なフィールドで働くことができるインターフェースで働くメソッドを持っていません、それではなぜそれが存在するべきですか?


0

うん、それはできません。なぜそうすべきでないのかについてコメントしているすべての人のために:

インターフェイスIを利用するクラスAがあるとします。クラスBはクラスAを拡張するため、Aのすべてのインターフェイスメソッドも継承します。

ここで、クラスAにプライベートメソッドが必要であるが、他のクラス(クラスBまたはAを必ずしも拡張しないクラスC)に対しても契約上定義する必要があると想像してください。

おそらく「初期化」メソッドの場合、Iインターフェイスを使用するすべてのクラスに必要です。しかし、明らかに私は初期化メソッドをパブリックにしたくありません....一度だけ使用するか、クラスが必要と見なすときに使用する必要があるため、すべてを意地悪に使用したいという理由だけではありません。

唯一の解決策は、回避策、またはインターフェイスなしでinitメソッドをクラス自体に強制することです。

その理由も確かにわかりますが、それでも役立つ場合があります。明らかに、OracleはJDK9でプライベートインターフェイスメソッドを許可していることに同意しています。

とにかく私がしたことは、単純なブール変数を配置することでした。これにより、一度設定した後、インターフェイスメソッド(プライベートである必要があります)にtrue(初期化= true)のフラグを付けることができます。その後、再度呼び出された場合、メソッドは単に何もしません。このようにして、インターフェイスメソッドをパブリックとして実装できますが、(私のクラスの)コンストラクターが最初にメソッドを呼び出すため、変数がtrueに設定され、再度呼び出すことはできません。

それ以外の場合、クラスの内部動作のみで使用する場合は、別の回避策を試す必要があります。おそらく、メソッド自体が使用時にフラグをオンまたはオフに設定します。フラグがfalseの場合、メソッドは何もしません(これは、誰かがクラスの外部からフラグを呼び出す場合です)。ただし、クラス独自のメソッドがそれを呼び出すと、すぐにフラグをtrueに設定し、次にメソッドを呼び出し、次にフラグをfalseに設定しますか?

結局のところ、ミュートのようなものです。おそらく今のところ、プライベートクラスをクラス自体に配置し、インターフェイスを完全に切り取る方がよいでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.