Java では、継承を作成および処理するときに、アクセス修飾子、つまりデフォルト (パッケージ プライベート)、 public
、protected
およびをいつ使用するかについて明確な規則がありますか?private
class
interface
30 に答える
公式のチュートリアルが役に立つかもしれません。
クラス | パッケージ | サブクラス (同一パッケージ) |
サブクラス (差分パッケージ) |
世界 | |
---|---|---|---|---|---|
public |
+ | + | + | + | + |
protected |
+ | + | + | + | |
修飾子なし | + | + | + | ||
private |
+ |
+ : アクセス可能
空白 : アクセス不可
(注意: 私は Java プログラマーではありません。Perl プログラマーです。Perl には正式な保護機能がありません。それが、おそらく私がこの問題をよく理解している理由です :) )
プライベート
ご想像のとおり、それが宣言されているクラスだけがそれを見ることができます。
パッケージ プライベート
宣言されたパッケージでのみ表示および使用できます。これは Java のデフォルトです (これを誤りと見なす人もいます)。
保護された
パッケージ プライベート + は、サブクラスまたはパッケージ メンバーから見ることができます。
公衆
誰もがそれを見ることができます。
公開済み
私が制御するコードの外側に表示されます。(Java 構文ではありませんが、この説明では重要です)。
C++ では、「フレンド」と呼ばれる追加のレベルが定義されています。
いつ何を使うべきですか?全体のアイデアは、情報を隠すためのカプセル化です。何かがどのように行われたかの詳細をユーザーからできるだけ隠したいと思うでしょう。なんで?後で変更しても、誰のコードも壊すことがないからです。これにより、オーバーホールしたばかりのコードを誰かが使用していることを心配することなく、最適化、リファクタリング、再設計、およびバグ修正を行うことができます。
したがって、経験則として、必要なだけ見えるようにすることです。プライベートから始めて、必要に応じて可視性を追加します。ユーザーが知る必要があることだけを公開してください。公開するすべての詳細は、システムを再設計する能力を圧迫します。
内部を公開して上書きできるようにするのではなく、ユーザーが動作をカスタマイズできるようにしたい場合は、多くの場合、それらの内臓をオブジェクトに押し込んで、そのインターフェイスを公開する方が良い考えです。そうすれば、新しいオブジェクトを簡単にプラグインできます。たとえば、CD プレーヤーを作成していて、「この CD に関する情報を探しに行く」を少しカスタマイズ可能にしたい場合は、これらのメソッドを公開するのではなく、すべての機能をそのオブジェクトに入れ、オブジェクトの getter/setter だけを公開します。このように内臓をさらけ出すことをケチることは、良い構成と関心の分離を促進します。
私は「プライベート」と「パブリック」だけに固執します。多くの OO 言語にはそれがあります。「Protected」は便利ですが、チートです。インターフェースがプライベート以上のものになると、それはあなたのコントロールの外にあり、使用法を見つけるために他の人のコードを調べなければなりません.
ここで、「公開済み」のアイデアが登場します。インターフェースを変更する (リファクタリングする) には、それを使用しているすべてのコードを見つけて、それも変更する必要があります。インターフェイスがプライベートの場合は問題ありません。保護されている場合は、すべてのサブクラスを見つける必要があります。公開されている場合は、コードを使用するすべてのコードを見つけに行く必要があります。これが可能な場合もあります。たとえば、内部使用のみの企業コードに取り組んでいる場合、インターフェイスが公開されているかどうかは問題ではありません。企業リポジトリからすべてのコードを取得できます。しかし、インターフェイスが「公開」されている場合、それを使用するコードが自分の制御外にある場合、あなたはうんざりします。そのインターフェイスをサポートしないと、コードを壊す危険があります。保護されたインターフェイスでさえ、公開されていると見なすことができます (これが、私が公開していない理由です)。
多くの言語は、公開/保護/非公開の階層的性質があまりにも限定的であり、現実に沿っていないと感じています。そのために特性クラスという概念がありますが、それはまた別の話です。
____________________________________________________________________
| highest precedence <---------> lowest precedence
*———————————————+———————————————+———————————+———————————————+———————
\ xCanBeSeenBy | this | any class | this subclass | any
\__________ | class | in same | in another | class
\ | nonsubbed | package | package |
Modifier of x \ | | | |
————————————————*———————————————+———————————+———————————————+———————
public | ✔ | ✔ | ✔ | ✔
————————————————+———————————————+———————————+———————————————+———————
protected | ✔ | ✔ | ✔ | ✘
————————————————+———————————————+———————————+———————————————+———————
package-private | | | |
(no modifier) | ✔ | ✔ | ✘ | ✘
————————————————+———————————————+———————————+———————————————+———————
private | ✔ | ✘ | ✘ | ✘
____________________________________________________________________
簡単ルール。すべてを非公開と宣言することから始めます。そして、ニーズが生じ、デザインがそれを保証するにつれて、一般に向けて進みます.
メンバーを公開するときは、表現の選択肢または抽象化の選択肢を公開するかどうかを自問してください。1 つ目は、観察可能な動作ではなく、実際の表現に対する依存関係が多すぎるため、避けたいものです。
原則として、サブクラス化によってメソッドの実装をオーバーライドしないようにしています。ロジックを台無しにするのは簡単すぎます。オーバーライドする予定がある場合は、abstract protected メソッドを宣言します。
また、オーバーライド時に @Override アノテーションを使用して、リファクタリング時に問題が発生しないようにします。
実際には、単純なグリッドが示すよりも少し複雑です。グリッドはアクセスが許可されているかどうかを示しますが、正確には何がアクセスを構成するのでしょうか? また、アクセス レベルは、ネストされたクラスや継承と複雑な方法で相互作用します。
「デフォルト」アクセス (キーワードがないことで指定) は、package-privateとも呼ばれます。例外: インターフェイスでは、モディファイアなしはパブリック アクセスを意味します。public 以外の修飾子は禁止されています。列挙型定数は常にパブリックです。
概要
このアクセス指定子を持つメンバーへのアクセスは許可されていますか?
- Member is
private
: member が呼び出しコードと同じクラス内で定義されている場合のみ。 - メンバーはパッケージ プライベートです: 呼び出し元のコードがメンバーのすぐ外側のパッケージ内にある場合のみ。
- メンバーは
protected
: 同じパッケージ、または呼び出し元のコードを含むクラスのスーパークラスでメンバーが定義されている場合。 - メンバーは
public
: はい。
アクセス指定子が適用される対象
ローカル変数と仮パラメーターは、アクセス指定子を取ることができません。これらは、スコープ規則に従って本質的に外部からアクセスできないため、事実上非公開です。
トップ スコープのクラスでは、public
および package-private のみが許可されます。この設計上の選択は、おそらく、パッケージ レベルで冗長になるためです (パッケージの継承はありません) protected
。private
すべてのアクセス指定子は、クラス メンバー (コンストラクター、メソッドと静的メンバー関数、ネストされたクラス) で使用できます。
注文
アクセス指定子は厳密に順序付けることができます
パブリック > 保護 > パッケージ プライベート > プライベート
public
これは、アクセスを最大限に提供し、最小限に抑えることを意味しますprivate
。private メンバーで可能なすべての参照は、package-private メンバーにも有効です。package-private メンバーへのすべての参照は、保護されたメンバーで有効です。(保護されたメンバーへのアクセスを同じパッケージ内の他のクラスに与えることは間違いと見なされていました。)
ノート
- クラスのメソッドは、同じクラスの他のオブジェクトのプライベート メンバーにアクセスできます。より正確には、クラス C のメソッドは、C の任意のサブクラスのオブジェクトで C のプライベート メンバーにアクセスできます。Java では、インスタンスによるアクセスの制限はサポートされておらず、クラスによる制限のみがサポートされています。(を使用してそれをサポートする Scala と比較してください
private[this]
。) - オブジェクトを構築するには、コンストラクターにアクセスする必要があります。したがって、すべてのコンストラクターがプライベートである場合、クラスはクラス内に存在するコード (通常は静的ファクトリー メソッドまたは静的変数初期化子) によってのみ構築できます。package-private または protected コンストラクターについても同様です。
- Java ではサブクラスのコンストラクターが暗黙的または明示的にスーパークラス コンストラクターを呼び出す必要があるため、プライベート コンストラクターしかないということは、クラスを外部でサブクラス化できないことも意味します。(ただし、それをサブクラス化するネストされたクラスを含めることはできます。)
内部クラス
内部クラスなど、ネストされたスコープも考慮する必要があります。複雑さの例としては、内部クラスにメンバーがあり、それ自体がアクセス修飾子を受け取ることができます。したがって、パブリック メンバーを持つプライベート 内部クラスを持つことができます。メンバーにアクセスできますか? (以下を参照してください。) 一般的なルールは、スコープを見て、再帰的に考えて、各レベルにアクセスできるかどうかを確認することです。
ただし、これは非常に複雑です。詳細については、 Java 言語仕様を参照してください。(はい、過去にコンパイラのバグがありました。)
これらがどのように相互作用するかについては、次の例を検討してください。プライベートな内部クラスが「リーク」する可能性があります。これは通常、警告です。
class Test {
public static void main(final String ... args) {
System.out.println(Example.leakPrivateClass()); // OK
Example.leakPrivateClass().secretMethod(); // error
}
}
class Example {
private static class NestedClass {
public void secretMethod() {
System.out.println("Hello");
}
}
public static NestedClass leakPrivateClass() {
return new NestedClass();
}
}
コンパイラ出力:
Test.java:4: secretMethod() in Example.NestedClass is defined in an inaccessible class or interface
Example.leakPrivateClass().secretMethod(); // error
^
1 error
関連する質問:
経験則として:
private
:クラススコープ。default
(またはpackage-private
):パッケージスコープ。protected
:(package scope + child
パッケージと同様ですが、異なるパッケージからサブクラス化できます)。保護された修飾子は、常に「親子」の関係を維持します。public
: どこにでも。
その結果、アクセス権を3つの権利に分割すると、次のようになります。
- (D)irect(同じクラス内のメソッドから、または「this」構文を介して呼び出す)。
- (R)eference(クラスへの参照を使用して、または「ドット」構文を介してメソッドを呼び出します)。
- (I)継承(サブクラス化による)。
次に、この単純なテーブルがあります。
+—-———————————————+————————————+———————————+
| | Same | Different |
| | Package | Packages |
+—————————————————+————————————+———————————+
| private | D | |
+—————————————————+————————————+———————————+
| package-private | | |
| (no modifier) | D R I | |
+—————————————————+————————————+———————————+
| protected | D R I | I |
+—————————————————+————————————+———————————+
| public | D R I | R I |
+—————————————————+————————————+———————————+
要するに
public
: どこからでもアクセスできます。protected
: 同じパッケージのクラスと任意のパッケージに存在するサブクラスからアクセスできます。- デフォルト (修飾子の指定なし): 同じパッケージのクラスからアクセスできます。
private
: 同じクラス内でのみアクセスできます。
Java で最も誤解されているアクセス修飾子はprotected
. サブクラスがそれを見ることができるという 1 つの例外を除いて、これは default 修飾子に似ていることがわかっています。しかし、どのように?うまくいけば混乱を明確にする例を次に示します。
2 つのクラスがあるとします。
Father
とSon
、それぞれが独自のパッケージに含まれています。package fatherpackage; public class Father { } ------------------------------------------- package sonpackage; public class Son extends Father { }
foo()
に保護されたメソッドを追加しましょうFather
。package fatherpackage; public class Father { protected void foo(){} }
このメソッド
foo()
は、次の 4 つのコンテキストで呼び出すことができます。が定義されている同じパッケージにあるクラス内
foo()
(fatherpackage
):package fatherpackage; public class SomeClass { public void someMethod(Father f, Son s) { f.foo(); s.foo(); } }
サブクラス内で、
this
またはを介して現在のインスタンスでsuper
:package sonpackage; public class Son extends Father { public void sonMethod() { this.foo(); super.foo(); } }
型が同じクラスの参照:
package fatherpackage; public class Father { public void fatherMethod(Father f) { f.foo(); // valid even if foo() is private } } ------------------------------------------- package sonpackage; public class Son extends Father { public void sonMethod(Son s) { s.foo(); } }
タイプが親クラスであり、定義されているパッケージ内にある参照 ( ) [これは、コンテキスト番号内に含めることができます。1]:
foo()
fatherpackage
package fatherpackage; public class Son extends Father { public void sonMethod(Father f) { f.foo(); } }
次の状況は無効です。
タイプが親クラスであり、が定義されているパッケージの外部にある参照 ( ):
foo()
fatherpackage
package sonpackage; public class Son extends Father { public void sonMethod(Father f) { f.foo(); // compilation error } }
サブクラスのパッケージ内の非サブクラス (サブクラスは保護されたメンバーをその親から継承し、それらを非サブクラスに対してプライベートにします):
package sonpackage; public class SomeClass { public void someMethod(Son s) throws Exception { s.foo(); // compilation error } }
プライベート
- メソッド、変数、およびコンストラクター
private と宣言されたメソッド、変数、およびコンストラクターは、宣言されたクラス自体内でのみアクセスできます。
- クラスとインターフェース
プライベート アクセス修飾子は、最も制限の厳しいアクセス レベルです。クラスとインターフェイスをプライベートにすることはできません。
ノート
public ゲッター メソッドがクラスに存在する場合、private と宣言された変数にクラス外からアクセスできます。スーパークラスで保護されていると宣言されている変数、メソッド、およびコンストラクターは、他のパッケージのサブクラスまたは保護されたメンバーのクラスのパッケージ内の任意のクラスによってのみアクセスできます。
保護された
- クラスとインターフェース
protected アクセス修飾子は、クラスおよびインターフェイスには適用できません。
メソッドとフィールドは保護されていると宣言できますが、インターフェイスのメソッドとフィールドは保護されていると宣言できません。
ノート
保護されたアクセスは、サブクラスにヘルパー メソッドまたは変数を使用する機会を与え、関連のないクラスがそれを使用しようとするのを防ぎます。
公衆
public と宣言されたクラス、メソッド、コンストラクター、インターフェイスなどは、他のどのクラスからもアクセスできます。
したがって、パブリック クラス内で宣言されたフィールド、メソッド、ブロックは、Java ユニバースに属する任意のクラスからアクセスできます。
- 異なるパッケージ
ただし、アクセスしようとしているパブリック クラスが別のパッケージにある場合は、パブリック クラスをインポートする必要があります。
クラスの継承により、クラスのすべてのパブリック メソッドと変数はそのサブクラスに継承されます。
デフォルト - キーワードなし:
デフォルトのアクセス修飾子とは、クラス、フィールド、メソッドなどのアクセス修飾子を明示的に宣言しないことを意味します。
- 同じパッケージ内
アクセス制御修飾子なしで宣言された変数またはメソッドは、同じパッケージ内の他のクラスで使用できます。インターフェイスのフィールドは暗黙的に public static final であり、インターフェイスのメソッドはデフォルトで public です。
ノート
静的フィールドを上書きすることはできません。上書きしようとしてもエラーは表示されませんが、例外として機能しません。
関連する回答
参考リンク
http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html http://www.tutorialspoint.com/java/java_access_modifiers.htm
違いは既に提供されているリンクにありますが、通常、どちらを使用するかは「最小知識の原則」に帰着します。必要最小限の可視性のみを許可します。
プライベート: クラスのみへの制限付きアクセス
デフォルト (修飾子なし) : クラスとパッケージへの制限付きアクセス
Protected : クラス、パッケージ、およびサブクラスへの制限付きアクセス (パッケージの内側と外側の両方)
Public: Accessible to class, package (all), and subclasses... In short, everywhere.
パッケージに表示されます。デフォルト。修飾子は必要ありません。
クラスのみに表示されます ( private )。
全世界に公開 ( public )。
パッケージとすべてのサブクラス ( protected ) に表示されます。
変数とメソッドは、呼び出される修飾子なしで宣言できます。デフォルトの例:
String name = "john";
public int age(){
return age;
}
プライベート アクセス修飾子 - プライベート:
private と宣言されたメソッド、変数、およびコンストラクターは、宣言されたクラス自体内でのみアクセスできます。private アクセス修飾子は、最も制限の厳しいアクセス レベルです。クラスとインターフェイスをプライベートにすることはできません。
public ゲッター メソッドがクラスに存在する場合、private と宣言された変数にクラス外からアクセスできます。
private 修飾子を使用することは、オブジェクトがそれ自体をカプセル化し、外部からデータを隠す主な方法です。
例:
Public class Details{
private String name;
public void setName(String n){
this.name = n;
}
public String getName(){
return this.name;
}
}
パブリック アクセス修飾子 - パブリック:
public と宣言されたクラス、メソッド、コンストラクター、インターフェースなどは、他のどのクラスからもアクセスできます。したがって、パブリック クラス内で宣言されたフィールド、メソッド、ブロックは、Java ユニバースに属する任意のクラスからアクセスできます。
ただし、アクセスしようとしているパブリック クラスが別のパッケージにある場合は、パブリック クラスをインポートする必要があります。
クラスの継承により、クラスのすべてのパブリック メソッドと変数はそのサブクラスに継承されます。
例:
public void cal(){
}
保護されたアクセス修飾子 - 保護されています:
スーパークラスで保護されていると宣言されている変数、メソッド、およびコンストラクターは、別のパッケージのサブクラスまたは保護されたメンバーのクラスのパッケージ内の任意のクラスによってのみアクセスできます。
protected アクセス修飾子は、クラスおよびインターフェイスには適用できません。メソッドとフィールドは保護されていると宣言できますが、インターフェイスのメソッドとフィールドは保護されていると宣言できません。
保護されたアクセスは、サブクラスにヘルパー メソッドまたは変数を使用する機会を与え、関連のないクラスがそれを使用しようとするのを防ぎます。
class Van{
protected boolean speed(){
}
}
class Car{
boolean speed(){
}
}
このページは、保護されたアクセス修飾子とデフォルトのアクセス修飾子についてよく書いています
.... Protected: Protected アクセス修飾子は少しトリッキーで、デフォルトのアクセス修飾子のスーパーセットと言えます。保護されたメンバーは、同じパッケージ内のアクセスに関する限り、既定のメンバーと同じです。違いは、保護されたメンバーは、親クラスが存在するパッケージの外部にある、メンバーが宣言されているクラスのサブクラスにもアクセスできることです。
しかし、これらの保護されたメンバーは、「継承によってのみパッケージの外部からアクセスできます」。つまり、メンバーがサブクラス自体に存在するかのように、他のパッケージに存在するサブクラス内のクラスの保護されたメンバーに直接アクセスできます。ただし、その保護されたメンバーは、親クラスの参照を使用して、パッケージ外のサブクラスでアクセスできません。....
David's answer は、各アクセス修飾子の意味を提供します。それぞれをいつ使用するかについては、外部使用 (その API) を目的としたすべてのクラスと各クラスのメソッドを公開し、それ以外はすべて非公開にすることをお勧めします。
時間が経つにつれて、一部のクラスをパッケージ プライベートにするタイミングと、サブクラスで使用するために保護された特定のメソッドをいつ宣言するかについての感覚が養われます。
Public Protected Default と private はアクセス修飾子です。
これらは、カプセル化、またはクラスの内容の表示と非表示を目的としています。
- クラスはパブリックまたはデフォルトにすることができます
- クラス メンバーは、public、protected、default、または private にすることができます。
Private はクラス外ではアクセスできません Default はパッケージ内でのみアクセスできます。パッケージとそれを拡張するクラスで保護されています。一般公開はどなたでも可能です。
通常、メンバー変数はプライベートに定義されますが、メンバー メソッドはパブリックに定義されます。
アクセス修飾子について考えるときは、次のように考えてください (変数とメソッドの両方に適用されます)。
public
--> どこからでもアクセス可能
private
--> 宣言されている同じクラス内でのみアクセス可能
default
となると、混乱が生じます。protected
default
--> アクセス修飾子キーワードがありません。これは、クラスのパッケージ内で厳密に使用できることを意味します。そのパッケージ以外にはアクセスできません。
protected
-->宣言されているパッケージdefault
の外部のサブクラスからアクセスできる同じパッケージ クラスとは別に、わずかに厳密ではありません。