- PR -

あるメソッドのオーバライドが他のメソッドに影響する場合

1
投稿者投稿内容
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-01-24 19:06
unibon です。こんにちわ。

オーバライドに関して、私が昔から抱いている基本的な疑問なのですが、
あるメソッドをオーバライドすると他のメソッドに影響してしまう場合があります。
具体的な例として java.util.ArrayList を継承して indexOf メソッドを改造した場合、
contains メソッドはどうなるか、という点についていくつか疑問があります。
#バージョンは問わないのですが、話が合うには共通のソースコードを見たほうが良いかもしれない、
#ということでとりあえずバージョンは 1.4 を仮定します。

(1) ArrayList クラスは contains メソッドの中で
  indexOf を呼び出していますが、そのため、
  indexOf の挙動を改造すると、
  知らぬ間に contains メソッドの挙動も変わってしまいます。
  しかし、そもそも API リファレンスを見ても contais のメソッドの中で
  indexOf を使っていることが分かりません。

(2) ということは継承するときは必ず親クラスのソースコードまでも見ないと
  漏れが生じる可能性があるということでしょうか。
  すなわち API リファレンスだけを見て継承することは怖くてできない、
  ということでしょうか。
  もしそうならば、API リファレンスは、
  クラスのインスタンスを new してそのメソッドを呼び出すだけの用途には使えても、
  クラスを extends する用途には十分ではないということでしょうか。

(3) 実装のスタイルとしてあるメソッドの中から、
  private でない別のメソッド(これはオーバライドされているかもしれない)を
  呼ぶことは好ましくないのでしょうか。

とくに疑問なのは、これらのようなことの決めは結構いい加減で、
その場その場で決めたりするものなのか、
それとも、○○派、□□流のようなきちんとした決めがあるのか、が分かりません。
#こういうのは Java より昔の C++ やさらにもっと昔からある基本的なことだと思うのですが、
#イマイチ分かっていません。
未記入
ぬし
会議室デビュー日: 2002/03/28
投稿数: 255
投稿日時: 2003-01-24 19:54
>(2) ということは継承するときは必ず親クラスのソースコードまでも見ないと
>  漏れが生じる可能性があるということでしょうか。
実装の継承はカプセル化を破壊するため,継承自体が必ずしも全面的に
お勧めできる機能というわけではありません.その危険性を承知した上で,
十分に用心して使うべきものです.

今回のような場合は,多分,普通は継承を使わないと思いますよ.
#どっちかというと委譲.
#ただ,厳密には委譲に当たるかどうかまでは未確認です.
t-wata
大ベテラン
会議室デビュー日: 2002/07/12
投稿数: 209
お住まい・勤務地: 東京
投稿日時: 2003-01-24 22:09
unibonさん
引用:

(2) ということは継承するときは必ず親クラスのソースコードまでも見ないと
  漏れが生じる可能性があるということでしょうか。


ソースコードを見た場合でも、スーパークラスに変更があると、
http://citeseer.nj.nec.com/531660.html
にあるような問題が発生します。(上記URLの右上の方から、PDFをダウンロードしてみてください)

引用:

(3) 実装のスタイルとしてあるメソッドの中から、
  private でない別のメソッド(これはオーバライドされているかもしれない)を
  呼ぶことは好ましくないのでしょうか。


Javadocにきちんと明記しておけばよいとは思いますが、私も、publicなメソッドから、publicな(finalでない)メソッドを呼ぶ事は好ましくないと思っています。

引用:

今回のような場合は,多分,普通は継承を使わないと思いますよ.


例えば、Listインターフェイスを実装していて、ArrayListと同じ振る舞いをし、indexOfだけ異なる振る舞いをするものを作りたい場合は、継承の方が便利ですよね。
但し継承する場合は、
> その危険性を承知した上で,十分に用心して使うべきものです.
ではありますが。

余談ですが、
http://www.cs.iastate.edu/~leavens/JML/index.html
こういうものもあるみたいです。
お犬様
ベテラン
会議室デビュー日: 2003/01/26
投稿数: 67
投稿日時: 2003-01-26 07:00
引用:

(1) ArrayList クラスは contains メソッドの中で
  indexOf を呼び出していますが、そのため、
  indexOf の挙動を改造すると、
  知らぬ間に contains メソッドの挙動も変わってしまいます。
  しかし、そもそも API リファレンスを見ても contais のメソッドの中で
  indexOf を使っていることが分かりません。


indexOf の仕様は java.util.List で定義されていますよね。
改造後の indexOf の挙動がこの仕様と矛盾しないのであれば
contains の挙動は変化するのは当然ですし、問題ないと思います。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-01-26 10:54
unibon です。こんにちわ。

引用:

悪夢を統べるものさんの書き込み (2003-01-24 19:54) より:
今回のような場合は,多分,普通は継承を使わないと思いますよ.
#どっちかというと委譲.
#ただ,厳密には委譲に当たるかどうかまでは未確認です.


今回の ArrayList に限った理由なのかもしれませんが、
実は、改造する際に、protected なフィールド、
modCount
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/util/AbstractList.html#modCount
にアクセスしたく、こうするためには、
委譲ではアクセスできないので継承にせざるを得ないと思っています。

引用:

t-wataさんの書き込み (2003-01-24 22:09) より:
ソースコードを見た場合でも、スーパークラスに変更があると、
http://citeseer.nj.nec.com/531660.html
にあるような問題が発生します。(上記URLの右上の方から、PDFをダウンロードしてみてください)


すみません。難しくてまだ読めていません。

引用:

お犬様さんの書き込み (2003-01-26 07:00) より:
indexOf の仕様は java.util.List で定義されていますよね。
改造後の indexOf の挙動がこの仕様と矛盾しないのであれば
contains の挙動は変化するのは当然ですし、問題ないと思います。


なるほど。こうやって決めてあるんですね。
API リファレンスの List クラスの contains と indexOf の所を見てみると、
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/util/List.html#contains(java.lang.Object)
では、

> リストに指定された要素が含まれている場合に true を返します。つまり、リストに、(o==null ? e==null : o.equals(e)) となる要素 e が 1 つ以上含まれている場合にだけ true を返します。

と規定され、

http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/util/List.html#indexOf(java.lang.Object)

では、

> 指定された要素がリスト内で最初に検出された位置のインデックスを返します。指定された要素がリストにない場合は -1 を返します。つまり、(o==null ? get(i)==null : o.equals(get(i))) を満たす最小のインデックス値 i を返します。そのようなインデックスがない場合は -1 を返します。

と規定されていました(制約が付けられていました)。
これらの2つの規定は似通っている(というか indexOf の概念が contains の概念を含んでいると読み取れる)ことから、
contains は内部的に indexOf を呼んで使えるはず、あるいは逆に、
indexOf は内部的に contains を呼んで使えるはず(あまり意味はありませんが補助的に使って悪くないはず)、
といった間接的な関係が成り立つことが導出できますね。

といことはオーバライドされるメソッドは、
class や interface にコードとして書ける引数の型や戻り値の型の規定だけではなく、
挙動も決めて JavaDoc に書いておくべき。
そして、継承する際には継承関係をすべてたどってみて JavaDoc に書かれていることを
すべて満たすような挙動としてなら改造できる、
ということで大丈夫なのかな、と思いました。
1

スキルアップ/キャリアアップ(JOB@IT)