polymorphism とか inheritance とか

wtnabeさんも書いていたことなんだけど、結構な人が「オブジェクト指向 = Javaオブジェクト指向」だと思っているようです。それはなんだかちょっと悲しいなぁ。
ということで適当にまとめることに挑戦。
まず、大前提として静的型付け言語ではメソッドシグネチャ*1 を宣言しておかないとメソッドの呼び出しができない*2。このメソッドシグネチャの集まりを型とかクラスとか呼んだりするするわけですな。
で、Java では継承と型階層を導入することで、異なるクラスのインスタンスをまとめてひとつの型で扱えるようにして、ポリモーフィズムを実現しているのである。要するに

class Base { }
class Derived extends Base { }

とあったときに、

Base a = new Base();
Base b = new Derived();

とできるわけだ。Base 型で宣言されたオブジェクトは実装がどうなっているかは分からないが、Base に宣言されたメソッドはすべて実装されて、呼び出し可能になっていることが保障される*3
当然、これは静的型付け言語故のやり方なのであって、動的型付け言語ではそもそもメソッドシグネチャを宣言する意味がないから「ポリモーフィズムと継承は表裏一体で使う」というのはオブジェクト指向全般について正しいわけではない。例えば、Python ではファイルオブジェクトのように扱える StringIO.StringIO というのクラスがあるが、これは別に決まったクラスを継承しているのではなく、ファイルオブジェクトと同じメソッドを備えるように実装されているだけだ。
さらに言えば、静的型付け言語であっても結局のところ、あるオブジェクトがどのようなメソッドを持っているかを宣言する方法があれば良いわけで、Java (や C++, C#) はそれに抽象データ型を使ったというだけの話である。Haskell のように型クラスを使う方法だってありだ。

*1:メソッド名、引数/戻り値の型、検査例外など

*2:リフレクションなんかはとりあえず置いておく

*3:nullの場合を除く