例)導入
javaの継承について、初めて学んだ時は、親クラスのprivateで変更されたものは子クラスに継承できないと思っていました。その後、勉強を深めていくうちに、もっと詳しく、いくつかの記事ブログ別の視点を参照してください:実際には、親クラスのものは、コンストラクタに加えて、privateを含む他のすべてのものを継承することができます。しかし、private修飾子があるため、このクラスでしか見ることができません。つまり、サブクラスが継承しても、それは見えないのです。
私は最初、え?父の遺産を相続したのに、自分では使えないの?どういう理屈なの。とにかく、private修飾子を継承すれば見えなくなるんだから、継承してもしなくても変わらないし、サブクラスが実際にprivateな内容を継承しているかどうかを確認する方法もないし、あまり深く考えませんでした。
ここで問題です。
今日、ポリモーフィズムを再検討していて、ある問題にぶつかりました。すでにご存知の方も多いと思いますが、ポリモーフィズムでは、インスタンス・メソッドにアクセスする場合、「コンパイルで左右を確認し、実行で右を確認する」というニーモニックに従っています。
つまり、コンパイル時には親クラスに対応するメソッドがなければコンパイルできませんが、実行時にはサブクラス内の特定のメソッドを実行するように実行され、書き換えられた場合はサブクラス内の書き換えられたメソッドが実行されます。書き換えがなければ、親クラスのメソッドが実行されるように見えますが、実際には、サブクラスの継承されたメソッドが実行されます。
このように、ポリモーフィックな形では、サブクラス固有のメソッドを呼び出すことはできませんし、呼び出す場合はトランスフォーム・ダウンしなければなりません。しかし、今日ふと思ったのですが、サブクラスにない親クラス固有のメソッドだったらどうでしょう? 私の理解では、親クラスのメソッドをprivateで変更しさえすれば、子クラスはそれを継承しません。このような場合、コンパイルはOKで、実行時にエラーが表示されるのではないでしょうか。
それからコードテストを始めました:
非公開メソッドを持つ親クラス
package demo07.test;
//親クラスで、私的に変更されたメソッド
public class Father
{
private void method()
{
System.out.println("親クラスに対してプライベートなメソッド");
}
}
サブクラス、何も書かれていません
package demo07.test;
//サブクラス、何も書かれていない
public class Son extends Father
{
}
テストカテゴリ
package demo07.test;
//
public class Test01
{
public static void main(String[] args)
{
Father father = new Son();
father.method();//エラーが報告された: 'method()'は'demo07'のプライベート・アクセスを持っている。.test.Father'
}
}
なぜなら、親クラスのメソッドはプライベートであり、他のクラスで使用することができないため、テストクラスではアクセスできないからです。コンパイラはエラーを報告します。
このクラスからしか見えないので、親クラスにメイン・メソッドを置いて、親クラスでテストすることにします。サブクラスはそのままで、親クラスを以下のように変更します:
package demo07.test;
public class Father
{
private void method()
{
System.out.println("親クラスに対してプライベートなメソッド");
}
public static void main(String[] args)
{
Father father = new Son();
father.method();
}
}
これで本当にエラーは報告されなくなり、コンパイルもパスできるようになりました。しかし、プログラムの実行結果ですが、私は驚きました。プログラムはエラーなしで実行されただけでなく、出力:親クラスprivateメソッド。何?状況は何ですか、なぜ正常に実行することができ、サブクラスは明らかにこのメソッドメソッドを持っていない、なぜ正常に実行できますか?
自分で調べてもわからなかったし、キーワード検索の仕方もわからなかったんです。それから先生に聞きに行ったのですが、あまりはっきりしないようで、どう説明していいかわかりませんでした。でも先生は、permission修飾子の見え方と関係があるかもしれない、と言ってくれました。
真実は明らかになりました。
先生のご指摘を聞いて、本当にpermission修飾子の見え方が原因なのか、この方向で考えてみました。つまり、親クラスのprivateメソッドは実際には子クラスに継承されているのですが、子クラスからは見えないということです。しかし、まだ問題があります。親のmainメソッドで親のメソッドメソッドを呼び出したのですが、privateはクラスから見えているので問題はありません。しかし、実行すると、親クラスからサブクラスのprivateメソッドが実行されるので、正常に実行されないはずですが、実際には正常に実行されます。
親クラスのメソッドが子クラスに継承される場合、そのメソッドのパーミッション修飾子はどのクラスに対するものなのでしょうか?
これと似たような写真を見たことがあるでしょう:
上の段落はちょっとキザですが、言いたいことは実はとてもシンプルです。何度か読めばわかるでしょう。
もしサブクラス用であれば、private修飾子の継承された内容はサブクラスでもアクセスできるはずですが、実際にはそうではないので、親クラス用であるはずです。しかし、そのように推測することはできません。private修飾子が継承可能かどうかを検証しているのであり、そのように推測することは、private修飾子が継承可能であるとすでに決定していることを意味します。ですから、permission修飾子が親クラスに固有のものであることをコードで証明しなければなりません。
パーミッション修飾子が親クラス用か子クラス用かを確認します。
親クラスとサブクラスが異なるパッケージにあり、親クラスにはプロテクトされたメソッドがあります。そして、親クラスがあるパッケージの下にテストクラスを作成し、テストクラス内にサブクラスオブジェクトを作成し、サブクラスオブジェクトが親クラスから継承されたプロテクトメソッドを呼び出せるかどうかを確認します。 コードは以下のようになります。
testパッケージの親クラス: package test;
package test;
//testパッケージの親クラスである
public class Father
{
protected void method()
{
System.out.println("親クラスによって変更されたメソッド protected");
}
}
何も書かないtest.testパッケージのサブクラス
package test.test;
import test.Father;
//test.test何も書かないパッケージの下のサブクラス
public class Son extends Father
{
}
test.testパッケージのテストクラスTest01
package test.test;
//test.testパッケージのテスト・クラスは
public class Test01
{
public static void main(String[] args)
{
Son son = new Son();
son.method();//エラーが報告された:'test'内の'method()'に保護されたアクセスがある。.Father'
}
}
testパッケージのテストクラスTest02。
package test;
import test.test.Son;
//testパッケージのテスト・クラスは
public class Test02
{
public static void main(String[] args)
{
Son son = new Son();
son.method();
}
}
案の定、子クラスと同じパッケージのテストクラスTest01では、このメソッドを呼び出すことができず、親クラスのprotectedによってメソッドが変更されていることを教えてくれました。しかし、親クラスと同じパッケージのテストクラス Test02 では、このメソッドは普通に呼び出せます。
これまでのところ、継承関係において、サブクラスが親クラスから継承したメソッドは、親クラス固有のパーミッション修飾子を持つことを独自にコードで検証しています!注:オーバーライドされた場合、メソッドのパーミッション修飾子はサブクラス固有のものになります!
水が落ちる
継承関係において、サブクラスが親クラスから継承したメソッドは、親クラス固有のパーミッション修飾子を持ちます。これで質問2の説明がつきます。サブクラスが継承したprivateメソッドも、このクラスだけが見ることができるので、サブクラスが継承したprivateメソッドを親クラスのmainメソッドで実行することはもちろん可能です。サブクラスは親クラスからプライベートメソッドを継承しているので、問題2が解決されれば、問題1も解決されます。もちろん、このメソッドは普通に呼び出すことができます。
これは、継承関係において、親クラスのプライベート・メソッドは子クラスにも継承できるが、継承されたメソッドは親クラスにしか見えないということを証明しています。もちろん、この結論は、多相形式ではインスタンスメソッドが呼び出されたとき、最終的に実行されるのはサブクラスのメソッドであるという前提で正しいものです。 この結論は正しいです。