javaにおけるprivateメンバの動きについて伺いたいことがございます。
基本的にスーパークラスのprivateなメンバへはメソッド・フィールドともにサブクラスからは
アクセスできないとのことですが、
例えば、以下のようなコードがあるとします。
//スーパークラスの定義
class SuperClass{
private String privateString = "スーパークラスのプライベートメンバ";
public void getter(){
System.out.println(this.privateString);
}
}
//サブクラス
class SubClass extends SuperClass{
}
//実行クラス
class RunClass {
static public void main (String args []){
SubClass subObj;
subObj = new SubClass();
subObj.getter();
}
}
上記のようなコードの場合サブクラスのインスタンスであるsubObjが
スーパークラスのpublicなメソッドを通じてサブクラスからスーパークラスのprivateメンバへアクセスが
できてしまっています。
これは、スーパークラスのprivateが隠蔽されていないのではないでしょうか?
果たして、このときいったサブクラスのインスタンスのsubObjはどういった動きをしているのでしょうか?
No.8ベストアンサー
- 回答日時:
>つまり、スーパークラスのメンバをオーバーライドしてもスーパークラスのメソッドは
>保持されたまま、単純にサブクラスでオーバーライドしたメソッドの方がスーパークラスより
>優先して呼び出されるというような意味合いでしょうか?
「優先」とはちょっと違ってて、基本的に SuperClass のメソッドは
Subclass に同名のメソッドを作ると「置き換えられ」ます。これが override です。
C++ とかだとこのへんの実装が丸見えなので、具体的な実装方法を覗いて見たい時は
JAVA より C++ が適しているかも。
override は OOP の「多態性」(ポリフォーニズム)を実現するための
ものなので、概念的な部分はこのキーワードで調べてみたらよいでしょう。
SubClass型のインスタンス(変数の型ではなくて、newした時の型)が
呼び出すメソッドは置き換えられた方のメソッドですが、
型を指定して呼び出す方法があり、それが super です。この場合、
指定された型に結びついたメソッドが呼び出されます。
No.6
- 回答日時:
だいたい正しいのですが、
>(5)スーパークラスで定義していたメソッドをサブクラスでオーバーライドすることによって
>スーパークラスでの定義を破棄し、サブクラスで定義したことになる。
>そのため、オーバーライドしたメソッドからはスーパークラスのprivateメンバへはアクセス
>することができなくなる。
はちょっとだけ違います。スーパークラスでのメソッドは破棄されずに残ってます。
サブクラスから override 前のスーパークラスのメソッドを呼び出すことが可能です。
これを使って override 前の処理に新たな処理を加えたりすることができます。
この回答への補足
>スーパークラスでのメソッドは破棄されずに残ってます。
サブクラスから override 前のスーパークラスのメソッドを呼び出すことが可能です。
superキーワードによるスーパークラスのメンバの呼び出しができるということですね。
つまり、スーパークラスのメンバをオーバーライドしてもスーパークラスのメソッドは
保持されたまま、単純にサブクラスでオーバーライドしたメソッドの方がスーパークラスより
優先して呼び出されるというような意味合いでしょうか?
No.5
- 回答日時:
No3 です
まだ、発想が逆です。
スーパークラスを 変える際にどういう仕組みだったら変えやすいか?
private な 変数は どう変えようが 影響しない。
アクセス云々にこだわるより、もっと大切なことがあるのです。リファクタリングやデザインパターンとか見るべきです。 テンプレートパターンとか FactoryMethod や Abstrct Factory とか
この回答への補足
うーん。
私が知るべきはデザインパターンなど上の層ではなくもっと基本のクラスを継承することによるサブクラスの詳細な動きなのではとおもっています。例えば
他の方が答えてくださっているような、サブクラスからなぜスーパークラスにアクセスできるのかとか、privateなメンバは継承されるのか否かとか・・・・・。
pivateなメンバに関しては諸々の文献で異なった見解を多数見受けられます。
ある書籍はprivateなメンバは継承できないとか、またある書籍はprivateなメンバももちろん継承されるとかかれていたり・・・そのようなあやふやな箇所があるので当初の質問をしています。
No.4
- 回答日時:
(a)あるクラスのprivateなメンバへは,別クラスのメソッドからは直接アクセスできない。
(b)別クラスのメソッドから あるクラスのpublicなメソッドを呼び出し,それを通じてあるクラスのprivateなメンバにアクセスすることならできる。
それが情報隠蔽です。
http://oshiete.goo.ne.jp/qa/7340001.html の私の回答ANo.2
--------
スーパークラスの getter() が
サブクラスにおいて同名メソッド getter() でオーバライドされているなら,
subObj.getter() という記述は,サブクラスで定義されたgetter()を呼び出します。
前述(a)のとおり,このメソッドからはスーパークラスのprivateStringには直接アクセスできません。
(ちなみに前述(b)のとおり,サブクラスのgetter()からスーパークラスのgetter()を呼び出してスーパークラスのprivateStringにアクセスすることはできます,念のため)
質問文に掲載されたコードでは,
サブクラスに同名メソッドgetter()のオーバライド定義がありませんから,
subObj.getter() という記述は,継承元のスーパークラスのgetter()を呼び出します。
getter()もprivateStringも同一クラスに存在しますから,このメソッドからprivateStringに直接アクセスすることができます。
この回答への補足
>(b)別クラスのメソッドから あるクラスのpublicなメソッドを呼び出し,それを通じてあるクラスのprivateなメンバにアクセスすることならできる。
それが情報隠蔽です。
なるほど、privateの仕様は定義した当該のクラス内部からのみアクセス可能という
重要な部分をpublicやprotectedを使用してprivateなメンバへアクセスできる
メソッドを定義してそれをサブクラスにコールさせることで間接的?にスーパークラス内部からアクセスしたように見せかけているようなものですね。
さらに
サブクラスでそのような間接的にアクセスさせるメソッドをオーバーライドさせてしまうと
オーバーライドしたメソッドはスーパークラスからは削除され(superというキーワードがありますが・・・・)サブクラスで初めて定義されたものとみなされ
スーパークラス内で定義されたメソッドからならアクセス可能という条件から外れてしまうため
スーパークラスのprivateなメンバへアクセスできなくなってしまうというわけですね。
#2の人への返信にも、付加したのですが
自分なりにまとめてみました。
おかしなところなどありましたら
是非、お聞かせいただきたいです。
https://twitter.com/1000_1000_/status/2331771146 …
上が醜ければ
https://p.twimg.com/Azxo60QCcAAxgEE.png:large
を参照ください。
No.3
- 回答日時:
発想が違うと思います。
オブジェクト指向は スーパークラスと派生クラスの結合の弱さを大事にします。つまり、発生クラスはそのままで
スーパークラスを変更する、その際、private な変数は一切消えて作り替えても、支障をきたさない。そうなってなければ、スーパークラスは変更できないわけです。
プログラムを変更する、そのことから 考えてください。
この回答への補足
ご回答ありがとうございます。
つまりは、基本的にprivateなメンバがあるクラスに関しては
extendsキーワードでクラス拡張するべきではないということでしょうか?
あるいは逆の意味・・・
クラス拡張を前提としたクラスをつくるのであれば
privateメンバを利用するべきではないということでしょうか?
では、質問のコードにもあるようにサブクラスからスーパークラスの
publicやprotectedメソッドを通してスーパークラスのprivateへアクセスできるのは
オブジェクト指向上好ましくないということですか?
No.2
- 回答日時:
>継承されたメソッド getter()はSubClass内のprivateStringというフィールドを
>見に行かなければいけないのではないでしょうか?
そうですよ。privateStringも継承されます。インスタンスはあくまで
SubClass型で SuperClass型ではありません。
そして SuperClass で private で宣言されたフィールドは
SuperClass で宣言されたメソッドからしかアクセスできません。
そのようにコンパイラがアクセスを制御するからです。
それから「隠蔽」というのは直接アクセスを禁ずるだけで間接的なアクセスはOKです。
もしそれさえも禁じてしまえば、親クラスの存在意義はなくなります。
この回答への補足
ご回答まことにありがとうございます。
個人的に、ちょっと考え違いをおこしていたようです。
そもそも継承とは、protectedおよびpublicを継承するためのものではなくて
classそのものを定義するサブクラス内に包含するといういみでよいでしょうか?
ちょっと自分なりに、まとめてみたのでごらんいただけますか?
https://twitter.com/1000_1000_/status/2331771146 …
上が醜ければ
https://p.twimg.com/Azxo60QCcAAxgEE.png:large
を参照ください。
要点としては、
(1)クラスの継承(拡張)とはクラスそのものをサブクラスの中に包含すること
かつ、privateなメンバもそれに含まれる。
(2)スーパークラスのprivateなメンバにはスーパークラスのメソッドからしか
アクセスできない。
(3)そして、スーパークラスをextendsしたサブクラスはそのサブクラス内に包含している
スーパークラスのprotectedおよびpublicにしかアクセスすることはできない。
(4)スーパークラスのprivateは当該のスーパークラスからしかアクセスすることができないが
スーパークラス内で定義したprotectedやpublicメソッドをサブクラスがコールしアクセスすることで
間接的にスーパークラス内からprivateメンバへアクセスしたことと同義となる。
(5)スーパークラスで定義していたメソッドをサブクラスでオーバーライドすることによって
スーパークラスでの定義を破棄し、サブクラスで定義したことになる。
そのため、オーバーライドしたメソッドからはスーパークラスのprivateメンバへはアクセス
することができなくなる。
というところでしょうか?
アップした図および、上記項目に解釈の間違いがあれば
是非、ご指摘いただいたいです。
よろしくお願いします。
No.1
- 回答日時:
privateの働きはここではsubObj.privateStringのように直接アクセスするのを禁止することや、
サブクラス内でthis.privateStringのようにアクセスするのを禁止する事です。
つまり、privateという変数はサブクラスを含む外部から、直接その変数名を指定してアクセスされることを禁止するだけです。
そしてあくまで、privateStringは外部からは見えていないので隠蔽されています。
この回答への補足
なるほど、わかりました。
しかしながら、
スーパークラスのメソッドgetter()は継承されてSubClassからアクセスしているのですよね?
そう解釈するのであれば継承されたメソッド getter()はSubClass内のprivateStringというフィールドを見に行かなければいけないのではないでしょうか?
なぜ、スーパークラスのprivateなメンバであるprivateStringという変数を見に行くのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・【お題】絵本のタイトル
- ・【大喜利】世界最古のコンビニについて知ってる事を教えてください【投稿~10/10(木)】
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・ハマっている「お菓子」を教えて!
- ・最近、いつ泣きましたか?
- ・夏が終わったと感じる瞬間って、どんな時?
- ・10秒目をつむったら…
- ・人生のプチ美学を教えてください!!
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
JAVA初心者です。
-
VB.Net: クラスの共有メソッド...
-
初歩的な メソッドの引数について
-
既存のデータファイルに追加書...
-
[String]の意味は?
-
String.containsの反対機能はあ...
-
Javaのコネクションやストリー...
-
メインメソッドのstatic
-
エクセルVBAで、条件に一致する...
-
「タイプ初期化子が例外をスロ...
-
vb.net オブジェクト指向につい...
-
範囲外の数値を代入したらエラ...
-
エクセルVBAのInputBoxメソ...
-
javaのコンパイルができません...
-
PDFファイルから別ウィンドウで...
-
ネスカフェ エクセラ と UCCク...
-
UTF-8のテキストファイルを開く...
-
IPアドレスのクラスAを取得して...
-
同じクラスにならない確率を教...
-
「天声人語」をインターネット...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Java初級 引数に適用できません
-
String.containsの反対機能はあ...
-
レコード件数の表示
-
YYYYMMDD書式の日付に対する適...
-
StringBufferからStringへキャ...
-
Strutsでチェックボックスの値...
-
Java初心者です、エラーの意味...
-
Google Apps Script で getRang...
-
C# でメソッドに送られてきたOb...
-
メソッドの引数に指定されてい...
-
Fileの読み取り専用の解除
-
なぜprotected overrideなのか
-
return new使用時
-
クラスを作るとメソッドの数が...
-
javaに"search"という関数 or ...
-
C# 点の描き方をおしえてくだ...
-
親の親のメソッドを呼ぶには?
-
Javaの関数名が長い?
-
CSVから読み込んだデータの保持...
-
別クラスのmainメソッドの実行
おすすめ情報