あるクラス3つのクラス A B C があり、
A は B のスーパークラス、B は C のスーパークラスだったとします。
また、3つのクラスそれぞれに protected の同じシグネチャのメソッド foo があり、
B.foo は A.foo をオーバーライドし、C.foo は B.foo をオーバーライドしています。
この状況で、C.foo メソッドの中から A.foo メソッドを呼ぶにはどうすればいいでしょうか。
C.foo メソッドから B.foo メソッドは super.foo で呼べますが、
A.foo メソッドの呼び方がわかりません。
ためしに C.foo メソッド内で A a = (A)this; とやってみましたが、
protected だからでしょうか、a から foo メソッドが呼べません。
super.super.foo も構文違反でした。
このようなことは Java のルールでは不可能なのでしょうか。
言語仕様は知りませんが、
C はあくまで B を継承しているのですから、
B が A の継承をやめる可能性も含め、
A のインターフェイスには関知しない方が
保守の面からみても妥当に思えます。
B が A を継承していることを意識している時点で
B の内部実装を意識している → カプセル化が成立していない
と考えることもできます。
すでに検討されていると思いますが、
素直に B クラスに A のメソッドを呼び出すメソッドを
別途作成する方が妥当ではないでしょうか。
C の視点では、B.Foo() ではなく、A.Foo() を呼びたい時点で
「意味が違う」のですから、シグネチャ(メソッド名)も
変わってしかるべきだと思います。
解決しました。
話を一般化するために、
あえて簡単な例を挙げましたが、
本当は Swing が提供するクラスを継承して、
一部の機能だけを拡張したかったのですが、
そのやり方が間違っていたために、
2階層上のオーバーライドメソッドを
呼ぶ必要に迫られていました。
何が問題で、どういうことだったのかを説明します。
DefaultStyledDocument を継承して、
insertUpdate メソッドでエレメント構造を変更する処理に
少し細工を施したいと思いました。
そこで、insertUpdate メソッドをオーバーライドし、
DefaultStyledDocument クラスの
insertUpdate メソッドが内部で行っている処理を参考にして、
自身でエレメント構造を変更する処理を書きました。
ところが、元々の DefaultStyledDocument クラスの
insertUpdate メソッドでは、最後にその親、
つまり AbstractDocument クラスの
insertUpdate メソッドを呼んでいます。
このメソッドでは、
ドキュメントの国際化のための(ユニコード用の)
もうひとつのルートエレメントに対して処理を施しています。
(一般的には、デフォルトルートの他に
もうひとつのルートが存在する)
こちらの方は自分で作る必要がないので、
僕がオーバーライドした insertUpdate メソッドでも、
同じように DefaultStyledDocument クラスの
insertUpdate メソッドを呼ぼうとしました。
つまり、自身から見て2階層親のオーバーライドメソッドを
呼ぼうとしていたのです。
suzuka さんのアドバイスを受けて、
よくよく考えてみたところ、
これは設計ミスだったことが分かりました。
自身でエレメント構造を構築したいのなら、
DefaultStyledDocument クラスではなく、
AbstractDocumentクラスを継承すべきだったんです。
そのことに気づいたら、
すっきりした自作クラスが作れました。
アドバイスありがとうございました。