- ベストアンサー
Java初心者が知りたい、privateメンバの動きとは?
- Java初心者が理解しておきたいprivateメンバの動きについて紹介します。スーパークラスのprivateなメンバへはサブクラスからはアクセスできないはずですが、一部の例外的なケースではアクセスが可能です。
- 例えば、サブクラスのインスタンスがスーパークラスのpublicなメソッドを通じてスーパークラスのprivateメンバにアクセスできるケースがあります。これはスーパークラスのprivateメンバが隠蔽されていない状態です。
- 具体的なコード例を挙げると、スーパークラスにprivateなフィールドがあり、サブクラスには特にフィールドやメソッドが定義されていない場合、サブクラスのインスタンスはスーパークラスのメソッドを通じてスーパークラスのprivateメンバにアクセスできることがあります。このような動きに注意しながら、Javaのprivateメンバの特性を理解しましょう。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
>つまり、スーパークラスのメンバをオーバーライドしてもスーパークラスのメソッドは >保持されたまま、単純にサブクラスでオーバーライドしたメソッドの方がスーパークラスより >優先して呼び出されるというような意味合いでしょうか? 「優先」とはちょっと違ってて、基本的に SuperClass のメソッドは Subclass に同名のメソッドを作ると「置き換えられ」ます。これが override です。 C++ とかだとこのへんの実装が丸見えなので、具体的な実装方法を覗いて見たい時は JAVA より C++ が適しているかも。 override は OOP の「多態性」(ポリフォーニズム)を実現するための ものなので、概念的な部分はこのキーワードで調べてみたらよいでしょう。 SubClass型のインスタンス(変数の型ではなくて、newした時の型)が 呼び出すメソッドは置き換えられた方のメソッドですが、 型を指定して呼び出す方法があり、それが super です。この場合、 指定された型に結びついたメソッドが呼び出されます。
その他の回答 (6)
- 中村 拓男(@tknakamuri)
- ベストアンサー率35% (674/1896)
だいたい正しいのですが、 >(5)スーパークラスで定義していたメソッドをサブクラスでオーバーライドすることによって >スーパークラスでの定義を破棄し、サブクラスで定義したことになる。 >そのため、オーバーライドしたメソッドからはスーパークラスのprivateメンバへはアクセス >することができなくなる。 はちょっとだけ違います。スーパークラスでのメソッドは破棄されずに残ってます。 サブクラスから override 前のスーパークラスのメソッドを呼び出すことが可能です。 これを使って override 前の処理に新たな処理を加えたりすることができます。
- eclipse2maven
- ベストアンサー率32% (33/101)
No3 です まだ、発想が逆です。 スーパークラスを 変える際にどういう仕組みだったら変えやすいか? private な 変数は どう変えようが 影響しない。 アクセス云々にこだわるより、もっと大切なことがあるのです。リファクタリングやデザインパターンとか見るべきです。 テンプレートパターンとか FactoryMethod や Abstrct Factory とか
補足
うーん。 私が知るべきはデザインパターンなど上の層ではなくもっと基本のクラスを継承することによるサブクラスの詳細な動きなのではとおもっています。例えば 他の方が答えてくださっているような、サブクラスからなぜスーパークラスにアクセスできるのかとか、privateなメンバは継承されるのか否かとか・・・・・。 pivateなメンバに関しては諸々の文献で異なった見解を多数見受けられます。 ある書籍はprivateなメンバは継承できないとか、またある書籍はprivateなメンバももちろん継承されるとかかれていたり・・・そのようなあやふやな箇所があるので当初の質問をしています。
- jjon-com
- ベストアンサー率61% (1599/2592)
(a)あるクラスのprivateなメンバへは,別クラスのメソッドからは直接アクセスできない。 (b)別クラスのメソッドから あるクラスのpublicなメソッドを呼び出し,それを通じてあるクラスのprivateなメンバにアクセスすることならできる。 それが情報隠蔽です。 http://okwave.jp/qa/q7340001.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/233177114633973760/photo/1/large 上が醜ければ https://p.twimg.com/Azxo60QCcAAxgEE.png:large を参照ください。
- eclipse2maven
- ベストアンサー率32% (33/101)
発想が違うと思います。 オブジェクト指向は スーパークラスと派生クラスの結合の弱さを大事にします。つまり、発生クラスはそのままで スーパークラスを変更する、その際、private な変数は一切消えて作り替えても、支障をきたさない。そうなってなければ、スーパークラスは変更できないわけです。 プログラムを変更する、そのことから 考えてください。
補足
ご回答ありがとうございます。 つまりは、基本的にprivateなメンバがあるクラスに関しては extendsキーワードでクラス拡張するべきではないということでしょうか? あるいは逆の意味・・・ クラス拡張を前提としたクラスをつくるのであれば privateメンバを利用するべきではないということでしょうか? では、質問のコードにもあるようにサブクラスからスーパークラスの publicやprotectedメソッドを通してスーパークラスのprivateへアクセスできるのは オブジェクト指向上好ましくないということですか?
- 中村 拓男(@tknakamuri)
- ベストアンサー率35% (674/1896)
>継承されたメソッド getter()はSubClass内のprivateStringというフィールドを >見に行かなければいけないのではないでしょうか? そうですよ。privateStringも継承されます。インスタンスはあくまで SubClass型で SuperClass型ではありません。 そして SuperClass で private で宣言されたフィールドは SuperClass で宣言されたメソッドからしかアクセスできません。 そのようにコンパイラがアクセスを制御するからです。 それから「隠蔽」というのは直接アクセスを禁ずるだけで間接的なアクセスはOKです。 もしそれさえも禁じてしまえば、親クラスの存在意義はなくなります。
補足
ご回答まことにありがとうございます。 個人的に、ちょっと考え違いをおこしていたようです。 そもそも継承とは、protectedおよびpublicを継承するためのものではなくて classそのものを定義するサブクラス内に包含するといういみでよいでしょうか? ちょっと自分なりに、まとめてみたのでごらんいただけますか? https://twitter.com/1000_1000_/status/233177114633973760/photo/1/large 上が醜ければ https://p.twimg.com/Azxo60QCcAAxgEE.png:large を参照ください。 要点としては、 (1)クラスの継承(拡張)とはクラスそのものをサブクラスの中に包含すること かつ、privateなメンバもそれに含まれる。 (2)スーパークラスのprivateなメンバにはスーパークラスのメソッドからしか アクセスできない。 (3)そして、スーパークラスをextendsしたサブクラスはそのサブクラス内に包含している スーパークラスのprotectedおよびpublicにしかアクセスすることはできない。 (4)スーパークラスのprivateは当該のスーパークラスからしかアクセスすることができないが スーパークラス内で定義したprotectedやpublicメソッドをサブクラスがコールしアクセスすることで 間接的にスーパークラス内からprivateメンバへアクセスしたことと同義となる。 (5)スーパークラスで定義していたメソッドをサブクラスでオーバーライドすることによって スーパークラスでの定義を破棄し、サブクラスで定義したことになる。 そのため、オーバーライドしたメソッドからはスーパークラスのprivateメンバへはアクセス することができなくなる。 というところでしょうか? アップした図および、上記項目に解釈の間違いがあれば 是非、ご指摘いただいたいです。 よろしくお願いします。
- 500cii
- ベストアンサー率50% (14/28)
privateの働きはここではsubObj.privateStringのように直接アクセスするのを禁止することや、 サブクラス内でthis.privateStringのようにアクセスするのを禁止する事です。 つまり、privateという変数はサブクラスを含む外部から、直接その変数名を指定してアクセスされることを禁止するだけです。 そしてあくまで、privateStringは外部からは見えていないので隠蔽されています。
補足
なるほど、わかりました。 しかしながら、 スーパークラスのメソッドgetter()は継承されてSubClassからアクセスしているのですよね? そう解釈するのであれば継承されたメソッド getter()はSubClass内のprivateStringというフィールドを見に行かなければいけないのではないでしょうか? なぜ、スーパークラスのprivateなメンバであるprivateStringという変数を見に行くのでしょうか?
補足
>スーパークラスでのメソッドは破棄されずに残ってます。 サブクラスから override 前のスーパークラスのメソッドを呼び出すことが可能です。 superキーワードによるスーパークラスのメンバの呼び出しができるということですね。 つまり、スーパークラスのメンバをオーバーライドしてもスーパークラスのメソッドは 保持されたまま、単純にサブクラスでオーバーライドしたメソッドの方がスーパークラスより 優先して呼び出されるというような意味合いでしょうか?