インターフェースで保護


111

interface定義内のすべてのメソッドが暗黙的にあるのはなぜpublicですか?protectedメソッドが許可されないのはなぜですか?


22
非常に良い質問です。Javaの他のほとんどすべてのことについて、私は選択の真の理由を見つけましたが、これについては私が見つけていません。同じパッケージ内の別のクラスが実装メソッドでこのメソッドを使用できるようにするインターフェイスで保護されたメソッドを定義することは完全に理にかなっています。そのメソッドを公開する必要はありません。パッケージメンバー、残りの世界へ。
Markus A.

4
@MarkusA。しかし、インターフェースは双方向に機能します。つまり、現在のパッケージの外部のクラスによって実装することもできます(そして、おそらくこのパッケージ内のメソッドに引数として渡されます)。現在のパッケージの外部にあるクラスは、パブリックインターフェイスの「保護された」メソッドをどのように実装できますか?
MartinStettner 2013年

8
@MartinStettner:そうではありません。それがポイントになります。パッケージには、インターフェイスを実装する関連のない複数のクラスが含まれている場合があり、そのインターフェイスタイプの参照を受け取るコードが特定の方法で動作することを保証する必要があります。そのような保証は、外部のコードがその契約に反する方法で動作しているときにインターフェースの実装を要求することを防ぐことができれば、はるかに強力になる可能性があります。
スーパーキャット2013年

1
@MarkusA。あなたは良い点を上げました、あなたはJava 9のモジュールシステムで
Nir Alfasi

1
インターフェースにprotectedmethod がある場合、すべての実装クラスはインターフェースのサブタイプと見なされます。これらすべてのクラスは、保護されたメソッドにアクセスできます。それは作るdoesntのprotected役に立たない方法でキーワードを? メソッドにこのインターフェイス保護キーワードを実装するユーザーを制限する方法がない限り、役に立ちません。私が間違っていれば私を修正してください!
amarnathは、

回答:


67

なぜなら、インターフェースは「クラスの外から見えるもの」を意味することになっているからです。非公開メソッドを追加しても意味がありません。


16
しかし、インターフェイスと同じパッケージのメンバーのみが「クラスの外から見ることができる」関数を持たないのはなぜですか?これを望んでいたいくつかのユースケースがありました。
Markus A.

5
@MarkusA。私はこれが遅いことに気づきますが、それからあなたは完全abstract classにを作ることがinterfaceできます。これは、interfaceJavaで取得する複数の実装の利点を失うことを認められますが、他のいくつかのパッケージの制限に準拠する契約を正直に確立することは、そのパッケージの外で独自の実装のメソッドに実際にアクセスできないため、テスト不可能で混乱を招きます。 。
pickypg 2013

10
@pickypgしかし、インターフェースを実装するクラスがすでに別のクラスを拡張している場合、別のクラスを拡張させることはできません。パッケージ内でのみ使用されるインターフェースについては、混乱することはないと思います。
フラマ2014年

24
@ Raveline、-1これは、「インターフェイスがクラスの外から見えるものを意味することになっているのはなぜですか?」Java 8ではすでにインターフェースでメソッド本体が許可されているので、保護された抽象メソッドも許可しないのはなぜですか?
Pacerier 2014

8
私はよくこの説明を読みますが、それは私見では間違っています。インターフェースは、OOP、通信API、ハードウェアのいずれの場合でも、「標準交換プロトコル」のようなものです。私のPCのUSBポートは明らかにパブリックインターフェイスです。しかし、私のメインボードのキーロックケースの裏側にあるピンは、オプションのUSBポートへのアクセスを提供し、明らかに「保護された」インターフェースです。次に、BIOSチップがあります。これも標準化されたインターフェイスですが、決して公開されることはありません。正確な詳細を非公開で知っている企業はわずかです。そのため、もちろん、インターフェースはあらゆる可視性を持つことができます!なぜOOPではないのですか?
Foo Bar

55

よく引用される理由は「インターフェースがパブリックAPIを定義する」ということですが、それは単純化しすぎだと思います。(そして、それは循環論理の「におい」も。)

アクセス修飾子が混在するインターフェースがあることは無意味ではありません。たとえば、一部はパブリックで、一部はインターフェースと同じパッケージ内の他のクラスに制限されています。実際、これは場合によっては非常に便利なIMOです。

実際、インターフェースのメンバーを暗黙的にパブリックにする理由の一部は、Java言語を単純にすることだと思います。

  • 暗黙的にパブリックインターフェイスメンバーを使用すると、プログラマーが処理しやすくなります。メソッドアクセス修飾子がランダムに選択されたコード(クラス)を何回目にしましたか?多くの「普通の」プログラマーは、Java抽象化境界を管理する最善の方法を理解することが困難です1。インターフェイスにpublic / protected / package-privateを追加すると、インターフェイスがさらに難しくなります。

  • 暗黙的なパブリックインターフェースメンバーは、言語仕様を単純化します。そのため、Javaコンパイラの作成者と、Reflection APIを実装する人々の作業が簡素化されます。

「インターフェースがパブリックAPIを定義する」という考え方は、おそらく、言語設計の決定を単純化した結果(または特性)であり、逆ではありません。しかし実際には、Java設計者の頭の中では、おそらく2つの考え方が並行して発展してきました。

いずれにしても、中RFEに公式対応JDK-8179193それは、Javaの設計チームが決めたことを明らかにし2を許可することをprotectedインターフェイス上では少しの本当の利益のために複雑になります。証拠見つけたことを@skomisaに感謝します。

RFEの証拠が問題を解決します。それが追加されていない公式の理由です。


1-もちろん、一流のプログラマーはこれらのことについて問題はなく、アクセス制御機能の豊富なパレットを歓迎するかもしれません。しかし、彼らのコードが他の誰かに引き渡されて維持されるとどうなりますか?

2-あなたは彼らの決定または彼らの述べられた推論に同意しないかもしれませんが、それは愚かです。


21

この質問は、Java 8のデフォルトメソッドの導入によって再開されたと言わざるを得ません。現在取り組んでいるプロジェクトは、インターフェースの基本的な性質と同様に、実装から意図を抽象化することを目的としています。

「デフォルトの保護」メソッドを使用してコードを大幅に簡略化できる場合がいくつかあります。インターフェースは依然としてJava 7ロジックに固執しているため、実際には機能しないことがわかりました。上記の理由から、通常の保護されたメソッドは特に意味がありません。しかし、デフォルトのパブリックメソッドが、変更される可能性が低く、保護されたメソッドによって提供できる低レベルのリソースを必要とする場合、「デフォルトの保護」機能を使用すると、よりクリーンなコードが維持されるだけでなく、将来のユーザーが保護されます。偶発的な虐待。

(これにより、コードを過度に複雑にする必要があるという事実は変わりませんが、不要な要約を使用します。ただし、機能のリクエストをOracleに送信するつもりです。)


100%同意します。抽象クラスは、デフォルトメソッドが導入される前は賢明な代替手段でした。ただし、それらが多重継承に課す制限は、完全ではないことを意味します。デフォルトのメソッドを持つインターフェースは通常、JDK 1.8以降の世界ではより優れた代替手段ですが、状態を保存できないため、他の抽象メソッドの定義に依存して状態を公開します。つまり、状態は公開されます。あなたが欲しい。
Jermy Krieg神父

10

インターフェイスがパブリックAPIを定義しているためです。保護されているものはすべて、インターフェースに属さない内部の詳細です。

保護された抽象メソッドで抽象クラスを使用できますが、インターフェースはパブリックメソッドとパブリック静的最終フィールドに制限されています。


5
「インターフェースがパブリックAPIを定義しているため」と述べました。では、インターフェイスでpublicAPI のみを定義する必要があるのはなぜですか。「内部の詳細」と「実装の詳細」にprotectedは違いがあります。Javaは、サブクラス化できるすべての人公開されたパブリックインターフェイスであり、基本的には全世界なので、内部の詳細ではありません。
Pacerier 2014

1
Java 8のデフォルトのメソッドではもう当てはまりません。
マリオロッシ

@MarioRossiまた、Java 9のプライベートインターフェイスメソッドではもう当てはまりません。
skomisa

7

おそらく、それはインターフェースであるため、つまり、クライアントにインスタンスで何ができるかを伝えるのではなく、何ができないかをクライアントに伝えるためです。


1
インターフェースがサブクラスに、実装を外部に公開せずにサブクラスに何ができるかを伝えることができなかった理由はわかりません。これは、抽象クラスを完全な代替として使用できるようになったときに行われた設計上の決定でした。しかし、インターフェイスのデフォルトメソッドの出現により、抽象クラスは不完全な代替手段になりました。
ジェレミークリーク神父

6

インターフェイスは保護されたメソッドを許可するべきだと私は強く感じています。インターフェースは全世界の誰にでも見えるようにすべきだと誰が言ったのですか?「通常の」(read:incompetent)プログラマーを混乱させる可能性があるという点について:OOPの多くは、オブジェクト、クラス、パッケージなどを適切に構造化することです。はるかに大きな問題。Javaはその種のもののために構築されました。


これは質問の答えにはなりません。
スティーブンC

5

ここでのいくつかの回答では、循環メソッドを使用して、インターフェイスメソッドを保護できない理由を説明しています。

それは何の説明にもなりませんが、幸いなことに、数年前に誰かがインターフェースの保護されたメソッドの拡張リクエストをJDKバグとして提起し、問題に光を当てました:

インターフェイスの保護されたメソッド:パッケージ間で共有

Javaでは修飾子が少し制限されているため、パッケージ間でメソッドを共有する方法はパブリックメソッドに制限されています。メソッドを公開するのは危険な場合がありますが、適切な修飾子がないために必要です。私のソリューションはこの制限を克服しています。

現在、Java言語仕様では、インターフェースメソッドの保護修飾子を許可していません。この事実を利用して、この新しい機能のインターフェースメソッドにprotectedを使用できます。

インターフェースメソッドが保護されているとマークされていて、インターフェースが別のパッケージのクラスによって実装されている場合、メソッドはパブリックである必要はありませんが、プライベートまたは少なくともパッケージで保護されている可能性もあります。メソッドは表示されますが、クラスがそれを宣言し、さらにインターフェイスのソースパッケージ(およびサブパッケージ)で表示されるものは何ですか。

このようにして、よく知られたパッケージ間で特定のメソッドを共有できます。

そして、これはステータスで閉じられたその拡張リクエストへの応答Won't fixです:

この提案は、実際の利益がほとんど得られない複雑さと特殊なケースを追加する方法で問題を解決しようとします。この問題を解決する一般的な方法は、パブリックインターフェイスを実装するプライベートクラスを用意することです。実装メソッドはパブリックですが、プライベートクラス内にあるため、プライベートのままです。

Java 9以降で利用可能な代替手段は、クラスとメソッドをパブリックにすることですが、一般的なパブリックにエクスポートされるのではなく、特定の「フレンド」モジュールへの限定エクスポートを持つモジュール内にあります。

したがって、そのバグレポートからの信頼できるポイントは次のとおりです。

  • 現在の状況は変わりません。インターフェイスがprotectedメソッドをサポートすることはほとんどありません。
  • protectedインターフェイスでメソッドをサポートしないことの正当性は、「実際の利益がほとんどないために複雑さと特別なケースが追加される」ことです。
  • Java 9以降、パッケージレベルのメソッドへのアクセスを提供するための代替アプローチがあります。Javaプラットフォームモジュールシステム(JPMS)を使用してクラスとメソッドをパブリックにしますが、一般のパブリックにエクスポートするのではなく、特定の「フレンド」モジュールに限定エクスポートされたモジュール内で使用します

4

実装クラスはインターフェースで宣言されたすべてのメソッドを実装する必要があるため、実装クラスが別のパッケージにある場合はどうなりますか?


2

インターフェイス説明したようなものを使用したい場合は、抽象クラスまたはネストされたインターフェイスを使用してください。

インターフェイススタイルに関するコードスタイルの抜粋ですが、メソッドにも適用されます。

インターフェースは、Javaプログラマーが自分のアプリケーションで参照および実装するために完全にアクセス可能なアプリケーションプログラミングインターフェース(API)を提供することを目的としているため、インターフェース変数は暗黙的にパブリックです。インターフェースは独自のものとは異なるJavaパッケージで使用される可能性があるため、パブリックな可視性により、プログラムコードが変数にアクセスできることが保証されます。

2

内部サブprotectedインターフェースを宣言することは良い習慣ですが、技術的にはJavaのインターフェースのように内部メソッドを宣言することはできません。

もちろん、パブリックインターフェイスを拡張する内部使用のための別のインターフェイスを作成できます。

package yourpackage;

public interface PublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

}

package yourpackage;

interface InternalInterface extends PublicInterface {

    void doAnyInternalThing1();

    void doAnyInternalThing2();

}

InternalInterfaceパッケージ内のインターフェースを使用できますが、PublicInterface(パブリックメソッド内の)サブタイプを受け入れる必要があります。

package yourpackage;

public class SomeClass {

    public void someMethod(PublicInterface param) {
        if (param instanceof InternalInterface) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

パッケージの外では、ユーザーはPublicInterface問題なく使用できます。

通常、プログラマーは同様の状況で抽象クラスを作成します。ただし、この場合、多重継承の利点は失われます。


1
パッケージ外では、ユーザーもを使用できますYourPublicInterface.Internal。ネストされたインターフェースを含むインターフェースのすべては、publicキーワードの有無に関係なくパブリックです。
グレッグRoelofs

1

同じパッケージへの可視性を制限したい場合が唯一のシナリオです。の他のすべての用途はprotected適用されません。具体的には、protected子孫の下位レベルの実装の詳細へのアクセスを提供するためにメソッドがよく使用されます。しかし、公開する下位レベルの実装がないため、インターフェースで宣言することは意味がありません。

そして、パッケージのシナリオでさえ、実際のインターフェースとは異なります。

おそらく必要なことを実現するには、2つのインターフェイスが必要です。1つは内部で使用するインターフェイスで、もう1つはパブリックAPIで公開するインターフェイスです。(内部のものは可能ですが、必ずしも公開のものを拡張する必要はありません。)または、他の人が指摘したように、抽象スーパークラス。


抽象スーパークラスは、それ自体がパッケージの外部の型によって派生するのを防ぐことができます。パッケージの作成者を信頼する、そのようなスーパークラスタイプの参照を受け取る人は、オブジェクトが要求どおりに動作することを保証できます。いくつかの一般的な機能を公開したいが、適切な階層に適合しない複数のクラスがパッケージにある場合(たとえば、1つは関数XとY、1つはYとZ、1つはXとZを実装します)、公開できると便利です。インターフェイスを使用する機能。ただし、インターフェイスタイプによって参照されるインスタンスは「本物」であることを約束します。
スーパーキャット2013年

0

プロテクトメソッドは、サブクラスが基本クラスを拡張する場合にのみ、サブクラスから常にアクセスできます。

インターフェースの場合、サブクラスはインターフェースを拡張しません。インターフェースを実装しています。

保護された方法は、を介してアクセスされている拡張ではない実装します


どのキーワード、どのキーワードでも、それは重要ではありません。
Alex78191

0

インターフェイスは、メソッドを外部の世界公開することを目的としています。したがって、これらのメソッドは本質的にパブリックです。ただし、同じクラスファミリー内に抽象化を導入したい場合は、インターフェイスと実装クラスの間に抽象化の別のレベル、つまり抽象クラスを作成することで可能です。以下に例を示します。

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}

2
しかし、誰にも見えないプライベートメソッドは、インターフェースで許可されています。
Alex78191

javaのインターフェースにはデフォルトのメソッドがあります。つまり、インターフェースは抽象クラスの多重継承をバイパスするための松葉杖です。次に、抽象クラスの多重継承が許可されるようにします。デフォルトのメソッドの競合は問題になりませんでした。
Alex78191

あなたが正しいです。Java 9以降、プライベートメソッドはインターフェイスで許可されています。これらを抽象化することはできません。主に他のデフォルトまたは静的メソッド(それらが静的である場合)によって、インターフェース内で実装および使用されます。
Stefanos Kargas

1
この答えは単に質問を無視します:なぜインターフェースはメソッドを保護できないのですか?保護されたメソッドは依然として「メソッドを外部の世界に公開」し「これらのメソッドは本質的にパブリックであるという主張は単に誤りです。言語はそのように設計されているため、公開されていますが、インターフェイスで保護されたメソッドを許可することもできます。OPは単に理由を尋ねています。
skomisa
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.