継承やオーバーライドで簡単にクラスを“拡張”しよう:【改訂版】Eclipseではじめるプログラミング(12)(1/4 ページ)
これからプログラミングを学習したい方、Javaは難しそうでとっつきづらいという方のためのJavaプログラミング超入門連載です。最新のEclipse 3.4とJava 6を使い大幅に情報量を増やした、連載「Eclipseではじめるプログラミング」の改訂版となります
上手にクラスの拡張を使ってプログラムを再利用しよう
オブジェクト指向プログラミング言語では、「プログラムの再利用が簡単にできるようになる仕組み」がいくつか採用されています。その1つにインターフェイスがありました。インターフェイスにより、「クラスが内部的に配列を使っているのか」「java.util.LinkedListを使っているのか」といった実装を気にすることなく、プログラミングができることを連載第9回の「プログラムを『変更』しやすくする“インターフェイス”」で解説をしました。
実は、インターフェイス以外にも「プログラムの再利用が簡単にできるようになる仕組み」があります。Javaでは、既存のクラスやインターフェイスを拡張するためのキーワード「extends」があります。プログラムを作成していて、「あるクラスにメソッドを1つだけ追加したクラスが欲しい」と思ったことはありませんか? そういったときに、既存のクラスを“拡張”できると、とても便利そうだと思いませんか?
これがJavaでは簡単に実現できるのです。とても便利なので、初心者のうちはついつい使ってしまうものですが、使い過ぎには注意が必要です。気が付いたら、何の役割を持つクラスだか分からない、ごちゃごちゃした機能を持つクラスが出来上がるかもしれないからです。今回は、キーワード「extends(拡張する)」に注目して、クラスの拡張について説明をします。
EclipseでJavaプログラミングを始める準備がまだの方は、連載第1回の「Eclipse 3.4で超簡単Javaプログラミング基礎入門」で準備をしておいてください。
「クラスを継承・拡張(extends)する」ってどういうこと?
「クラスの拡張」というのは、Javaにとって非常に重要な概念です。なぜなら実は、Javaのすべてのクラスは「java.lang.Object」というクラスを拡張したものだからです。java.lang.Objectクラスについては後で説明しますので、ここでは皆さんが作成するJavaプログラムは、「java.lang.Objectクラスを拡張したものに必ずなる」という点を覚えておいてください。
プログラミングを覚えたてのころは……
それでは、早速クラスの拡張について説明に入ります。プログラムを作成していると、ちょっとだけ処理が異なる似たようなクラスが複数必要となることがあります。プログラミングを覚えたてのころは、ソースコードをコピーして持ってきて、処理が異なる部分だけ手直しをして、似たようなクラスを複数作ってしまうものです(図1)。しかし、開発の現場でこういったことをすると、後で後悔をすることがよくあります。
こういったコピーしたコードが複数のクラスに存在するというのは、クラスの保守をする場合などに悪影響を及ぼすことが多いのです。
例えば、コピーしたコードの一部にバグが見つかって、それを修正する場合を考えてみてください。そのコードを張り付けた分だけ同じ修正を適用する必要が出てくるのです。バグ対応だけではありません。バージョンアップ時の機能強化をする際に、コピーしたコードへ追加をする必要が生じたときにも、同様の作業が発生してしまいます。
また、同じようなクラスをさらに追加する必要が生じたときのことも想像してみてください。似たようなクラスをいろいろなところで使っていると、どこへ追加すればいいのかよく検討をしないければいけなくなりますし、間違ったところへ追加をしてしまうと、思わぬバグを作り込んでしまう危険もあります。
Javaでは「extends」を使う
ですから、ソースコードをコピーして新しいクラスを作らずに済むような仕組みが必要です。こんなときは、Javaではextendsを使って、クラスの拡張をします。「クラスの拡張」をうまく使用することによって、プログラムの実装追加および実装変更を簡単に行えるようになります。
クラスの拡張を表す図はUMLを使って描くことができます。クラスAを拡張して、クラスBとクラスCを作成する場合の例を示します(図2)。図2のようにクラスは長方形で表し、クラスBとクラスCからクラスAに対して白抜き三角形の頂点が向くようにします。
コラム 「UMLでよく見る汎化(generalization)関係とは」
UMLでは、「クラスAとクラスBの関係は、汎化(generalization)関係にある」といいます。クラスAとクラスCも汎化関係にあります。図2は、「クラスBとクラスCは、クラスAとの共通点は多いが、若干違う性質を持ったり、振る舞いをするクラスだ」ということを意味していて、共通点の部分については、クラスAのプログラムに従うということです。
ですから、大きくとらえると「クラスBはクラスAである」といえます。もちろん「クラスCはクラスAである」ともいえます。このような「B is a A.」のような「is-a」の関係を持つクラスが存在している場合に、クラスの拡張は有効です。
extendsを使うことにより、すでに作成済みのクラスに実装されているコードに影響を与えることなく、新しいメソッドを追加して機能拡張したクラスが作れますし、既存のメソッドについても、処理内容を変更して違った振る舞いをするクラスを作れます。つまり、既存クラスの実装と異なる部分だけ新たに実装をすればいいということになり、既存クラスの実装を有効に利用できるのです(図3)。また、重複するコードがなくなるため、無駄がなくなり、コード量が少なくなります。
拡張は良いことばかりではない
ただし、良いことばかりではありません。元のクラスを作成したときには思いもしなかったような拡張を、後で実装してしまったりすると、思ったように動作しなくて困ったことになります。また、元のクラスにバグがあると、拡張したクラスにも影響が出ます。そもそも、拡張しやすいクラスを設計して作成するというのは難しいので、初心者のうちは自分が作成したクラスを拡張するということはあまり考えないでクラスを実装した方がいいかもしれません。
開発現場では、汎用化できそうなクラスは社内のエキスパートにお願いして用意してもらった方がいいでしょう。拡張されることを想定して設計され、きちんと実装されているクラスを元に拡張をするのはいいのですが、そうでない場合は問題が発生することがあります。
正しく実装されていれば、元となるクラスの修正は、拡張されたクラスへはその影響が出ないものですが、そうでない場合は、拡張されたクラスへ大きく影響してしまうことがあります。例えば、正しく実装されていないクラスを用意してしまって、それを拡張したクラスを大量に作成した後に、元となるクラスの修正が拡張したクラスへ影響を及ばすケースが発生すると、手直しするための余計な作業がたくさん生じてしまうのです。
「クラスの拡張」を理解するには、それが具体的にどういうものなのかを確認したり、実際に作成をして使ってみた方が早いです。次ページでは、サンプルコードを作成して実行してみることにしましょう。
コラム 「extendsはJava開発現場の常識」
もちろん、趣味のプログラムや学習のためのプログラムなどでは、どうせ自分しか使わないので、そういった心配をする必要はありません。理解を深めるために、いろいろ試してみるといいでしょう。また、標準ライブラリのクラスや、有名なライブラリに含まれるクラスや、社内のエキスパートが設計したクラスを拡張してプログラムを書くという場面は、実際の開発現場では多いはずです。
最近のJavaでWebアプリケーションを作成する場合には、必ず何らかのフレームワークを使い、そこではextendsが必ず出てきます。既存のクラスを拡張して自作クラスを作ることはよくありますから、extendsについては、きちんと理解をするようにしましょう。
Copyright © ITmedia, Inc. All Rights Reserved.