クラス

●オブジェクト指向プログラミングはなぜ必要?

その1 その2 No Link No Link No Link
プログラミング技術

Mizuho’s Web Site Coyright 2004 All rights reserved 

持っているほうが
望ましい知識/スキル
プログラマが必ず持っているべき知識/スキル
オブジェクト指向に関する知識/スキル
・オブジェクト指向全般に関する知識
・オブジェクト指向言語に関する知識
・問題対象からオブジェクトを抽出できるモデリング能力
図1 ●オブジェクト指向は、どちらかというと「プログラマが持っているほうが望ましい知識/スキルに属する。現在ではフレームワーク等が注目されているので必須になりつつある。
・OSに関する知識
・データ構造/アルゴリズムに関する知識
・バグが発生しやすそうな個所を見つけ出すカン
・コーディングの作法に関する知識
・プログラミング言語に関する知識
・開発ツールに関する知識
・問題対策から
 プログラム仕様を作成できる抽象化能力
・C++  ・Java
・Smalltalk
・Object Pascal(Delphi)
・Eiffel  ・C#
OOP
オブジェクト指向プログラミング
オブジェクト指向技術を使って
プログラム・コードを生成する
・ActiveXコントロール
・サーバーサイド・コンポーネント
 (EJBコンポーネントなど)
・アプリケーション・フレームワーク
コンポーネント/クラスライブラリ
再利用可能なソフト部品またはクラスの集まり
UML:United Modeling Language  EJB:Enterprise JavaBeans
CORBA:Common Object Request Broker Architecture  ORDB:Object Relation Database
・ピュアODB
・ORDB
ODB
オブジェクト指向データベース
プログラム中で利用するオブジェクトを保存しておく(永続化する)
・EJB
・CORBA
オブジェクト指向ミドルウェア
必要なオブジェクト(クラス)およびそれらの関係を抽出し、それぞれに持たせる処理を決める
OOA/OOD
・UML
・デザイン・パターン
オブジェクト指向分析/設計
必要なオブジェクト(クラス)およびそれらの関係を抽出し、それぞれに持たせる処理を決める
図2 ●オブジェクト指向プログラミングを取り巻く主な関連技術。このように整理すれば、用語に飲まれる心配はないだろう
メンバー変数
派生
メソッド
インスタンス
ポリモ-フィズム
カプセル化
クラス
図3 ●オブジェクト指向関連の用語がユーザーを悩ませる
継承
クラスE
関数E
データE
クラスD
関数D
データD
クラスC
関数C
データC
クラスB
関数B
データB
クラスA
関数A
データA
データE
データB
データD
データC
関数A
関数B
関数C
関数D
データA
関数E
プログラム
図4 ●クラスを利用すると、データと関数がまとまっていてわかりやすい。本来はモジュールのようなファイルでの管理も意識する必要があるが、ここでは無視している
オブジェクト指向プログラミング
従来の手続き型プログラミング
プログラム
リスト2 ●フィールドの頭の「public」を「private」に変更している
 public class Sankaku {
   private double teihen;
   private double takasa;

   public void setInfo(double a, double b) {
    teihen = a;
    tasaka = b;
   }

   public double getMenseki(){
    return teihen * takasa / 2;
   }
 }
リスト1 ●Sankakuクラスは二つのフィールドと、一つのメソッドを持っている
 public class Sankaku {  --------------------------(1)
   public double teihen;  -------(3)             ↑
   public double takasa;  --------(3)

   public Sankaku() {   --------(4)
   }  ------------------------(4)

   public double getMenseki(){  ----(5)
    return teihen * takasa / 2;  ----(5)
   }  --------------------------(5)          ↓
 }  -------------------------------------------(1)

 public class RunTest{  --------------------------(2)
                                      ↑
   public static void main(string[ ] args){
    Sankaku a = new Sankaku();  --------(6)
    a.takasa = 10;
    a.teihen = 20;
    System.out.println(a.getMenseki());
   }                                  ↓
 }  -------------------------------------------(2)


メソッドC
フィールドC
サブクラス
クラスC1
メソッドB
フィールドB
クラスB1
サブクラス
メソッドA
フィールドA
スーパークラス
クラスA
メソッドC
フィールドC
メソッドA
フィールドA
クラスC0
メソッドB
フィールドB
メソッドA
フィールドA
クラスB0
図6 ●クラスをスーパークラスとサブクラスに切り分ける
直接アクセスできる
クラス
クラスの
利用者
メソッド
データ
悪い例
クラス
×
クラスの
利用者
メソッド
データ
アクセスできない
よい例
図5 ●データを直接アクセスさせるような仕様はなるべく避け、常にメソッドを通してアクセスできるようにするべきだ。
サーバーサイド・コンポーネントとはサーバー側で利用するためのソフト製品。
EJB
はEnterprise Java Beansの略で、Javaのコンポーネント仕様 Java Beansをサーバー側で使えるように拡張したもののこと。EJB仕様に基づくソフト製品は、サーバーサイド・コンポーネントの代表例の一つと言えます。
COBRAは Common Object Request Broker Architecture の略で、分散オブジェクト環境の標準仕様です。
UMLは United Modeling Language の略で、オブジェクト指向分析/設計における標準モデリング言語のことです。
パターン:オブジェクト指向分析/設計における”定石”のことを指します。デザイン・パターンやアナリシス・パターンに加えて、「やってはいけないパターン」のアンチパターンなどがあります。
 ここでは、日経ソフトウェア2000年9月号に掲載されていた『オブジェクト指向プログラミングへジャンプ!!』田中淳氏の文書から抜粋したものを掲載します。時間的には少し古いものですが、オブジェクト指向のイントロダクションとしてふさわしいと思ったからです。あくまで私のメモですが、うなづける点や思い出すことも多いのではないかと思ってます。最初に、出てくる用語を少し掲載してから本題に入ります。

*1 例えばSmalltalkというオブジェクト指向言語では、クラスのことをオブジェクトとも呼んでいます。多だし他の言語/ツールでは、インスタンスのことをオブジェクトと呼ぶこともあります。このようにオブジェクト/クラス/インスタンスの使い分けが統一されていない点も、ユーザーの混乱を招く一因となっています。
*2 Javaの「new」はVBでオブジェクトを作るときに使う「New」とほとんど同じ役割です。
*3 VBでは「set=NewCTest」と書きます。

 ここでは、「クラス/インスタンス」「カプセル化」「継承」「ポリモ-フィズム」という四つのキーワードを学びます。(小野亮氏)

 オブジェクト指向でまず引っかかってしまうのは、特有の用語がいっぱい出てくることです(図3)。これはIntroでも挙げた通りです。
 これらのキーワードをまったく知らずに、オブジェクト指向プログラミングをするのはまずムリでしょう。しかし、だからといって、それらすべてをきっちり学ぶ必要はありません。私たちの目標はオブジェクト指向の研究者になることではなく、あくまでもオブジェクト指向プログラミングができるようになることです。とりあえず「こんなものだ」というイメージがつかめさえすれば十分でしょう。
 そこで以下では、どうしてもこれだけは知っておくべきというオブジェクト指向のキーワードを四つ取り上げて、それらがどのような意味を持つかを順に解き明かしていくことにしましょう。サンプルはJava言語で記述しました。現時点では、オブジェクト指向プログラミングを学ぶためにはJavaを使うのがもっとも適していると言えるからです。ただ、Javaの文法を知らなくてもわかるようにするつもりなので、安心して読み進めてください。
 オブジェクト指向プログラミングにおける「オブジェクト指向」とは、本当に大雑把に言ってしまえば「プログラム・コードをすっきりさせるもの」にほかなりません。コードがすっきりするから、あとあと変更しやすくなったり、コードの一部を再利用しやすくなったりするわけです。
 コードに限らず、物事を「すっきりさせる」ためにはどうするでしょう。普通は「整理する」ことから始めるのではないでしょうか。
 整理するとは「似たようなものをまとめる(グループ化する)」と言い換えてもよいかもしれません。このグループ化した単位のことを、オブジェクト指向では「クラス」と呼びます。
 一方の「インスタンス」とは何でしょうか。これは、世の中にある一つひとつの存在のことを指します。例えば、タイ焼きを例にとればすでに焼きあがったそれぞれのタイ焼きがインスタンスとなります。これらは「あんこ入り」「クリーム入り」「ちょっと焦げてる」などそれぞれ違いがあります。でも、どれも「タイ焼き」である点では共通しています。つまり、これらのインスタンスは「タイ焼き」というクラス(グループ)に属しているわけです。
 見方を逆にすると、「タイ焼き」というクラスは設計図の役割を果たしていると見ることができます。この設計図をもとに「あんこ入りタイ焼き」などの具体的なインスタンスを作り出しているわけです。まさにクラスは、タイ焼きの型の役割を果たしているのです。
 さて、オブジェクト指向の「オブジェクト」はクラスのことなのでしょうか、インスタンスのことなのでしょうか。ちょっとあいまいですが、オブジェクト指向が「コードをすっきりさせる」ものであることを考えると、そのすっきりさせる単位であるクラスがオブジェクトであると見なすほうが自然なのかもしれません*1
 もう少し話を具体的にしましょう。プログラム・コードの二大構成要素は「データ」と「関数」です。このコードをすっきりさせるためには、この中を「データとそれに関連ある関数」を組にして区切ってしまえばよいでしょう(図4)。その区切りの単位がクラスとなります。そしてプログラムを実行する際には、クラスをもとに実体となるインスタンスを作り(「インスタンスを生成する」と言います)、それをコードで用いることになります。
 クラスの中身(定義)についての説明は後回しにするとして、まずはすでに定義されたクラスをどう利用するのかを見てみましょう。Javaではクラスからインスタンスを生成するためにnew演算子を使います*2。いま、電卓の機能を持ったCDentakuクラスがあるとします。このCDentakuクラスを使う場合は以下のように記述します*3

 CDentaku a;
 a = new CDentaku();
または
 CDentaku a = new CDentaku();

このようにして、CDentakuクラスからインスタンスaを
生成しています。
 いまの例からおわかりのように、オブジェクト指向プ
ログらミングのクラスとインスタンスの関係は、データ型
と変数の関係とほとんど同じです。オブジェクト指向言
語では、クラス型という特別なデータ型から変数すなわちインスタンスを生成するわけです。

●まずは四つのキーワードを押さえておこう

*4 すべての関数を外部から使えるようにするとは限りません。データと同様に関数を「非公開」にすることもできます。
*5 カプセル化は、クラス内のフィールド(データ)や、それに関連のあるメソッド(関数)をひとまとめにするという意味でも使われます。
*6 C++ではメンバー関数ともいいます。
*7 protectedを指定したデータ(フィールド)またはメソッドは、それらを持つクラスと、そのクラスを継承したサブクラスから参照可能です。publicとprivateはあとで説明します。このほか、クラスに対してもアクセス指定子を使用することができます。Javaでは抽象クラスを表すabstract、C++では指定クラスから参照可能なfriendなどがその例です。
*8 C++ではメンバー変数といいます。VBでも同様です。

●カプセル化(情報隠ぺい) : 決まった方法で使ってもらおう

 さて、とりあえずコードを「クラス」という単位で区切ることができました。でも、単に区切っただけでは不十分です。次に、その区切り(クラス)の中でデータや関数をどのような形にするべきかを考えなければなりません。
 コードをすっきりさせるためには、それぞれのクラスができるだけ「独立」の関係になるようにすることが大切です。要は「クラスの中でできることは、すべて中でやるようにする」わけです。
 そのためには「クラスの中のデータを扱えるのは、基本的にそのクラスの関数だけ」とするのが有効なはずです。外部からそのクラスのデータにアクセスしたい場合は、必ずそのクラスの関数を通じてアクセスしてもらうようにするのです*4(図5)。丁度会社にいるあなたを訪ねてきた人に対して、まず受付を通してもらうようにお願いするようなものです。
 このようにクラスの中の情報に対して外部から直接アクセスできないようにし、アクセス方法を(そのクラスが持つ関数に)一本化することを「カプセル化」または「情報隠ぺい」と呼びます*5。カプセル化は、クラスと並んでオブジェクト指向プログラミングで欠かせないキーワードですので、ぜひ押さえておいてください。
 クラスが持っている関数のことを「メソッド」と呼びます*6。クラスを利用したい場合は、このメソッドを呼び出す形で利用することになります。ここで、先ほど例として挙げたCDentakuクラスがSetDataというメソッドを持っているとします。SetDataメソッドは、演算の対象となる二つの値をセットするものです。このSetDataメソッドを呼び出す場合は、例えば以下のように記述します。
 a.SetData(10,20)
「a」というのは、先ほど生成したインスタンスaのことです。このようにインスタンスを生成すると、元のクラスが備えている機能が利用できるようになります。当然、SetDataメソッドも利用できるわけです。Javaでは、このようにインスタンス名+ドット演算子(.)+メソッドという形で記述します。
 さて、いま言ったこととちょっと矛盾しますが、すべてのクラスで「外部にはデータを見せない」と杓子定規に決めてしまうのはちょっと不自然です。すべてのクラスから共通に使いたいデータや関数だって当然存在します。そのような場合には「これはどこからでも使えるよ」という仕組みもあったほうが便利です。コードをすっきりさせるためには、「整理する」だけでなく、「人間にとって自然な形をとる」ようにすることも大切なのです。情報隠ぺいといっても、すべての情報を隠すというわけではないことに注意してください。
 そこで多くのオブジェクト指向言語は「アクセス指定子」というものを用意しています。これを使って、クラスがもつ情報やメソッドを「どれだけ外に見せるか」を決めることができます。Javaではアクセス指定子として、public、private、protectedなどを用意しています*7
 ここまでわかったところで、実際にコードを見ていきましょう。まずはリスト1をご覧ください。三角形を表すSankaku(1)、そしてRunTest(2)という二つのクラスを定義しています。RunTestクラスはSankakuクラスからインスタンスを作って実行するためだけに作ったものです。C言語でいうところのmain関数に相当するものです。VBを使っている人は、フォームのLoadイベントの中でクラスからインスタンスを作っていると思ってください。Sankakuクラスは、底辺(teihen)、高さ(takasa)という二つのデータを持ちます(3)。もっと正確に言えば、底辺と高さのデータをいれるための”入れ物”を持っています。これらを「フィールド」といいます*8。これらに加えて、面積を求めるgetMensekiメソッドも備えています(5)。(4)はあとで説明することにして、(2)の中の処理に注目してください。まず最初に、Sankakuクラスのインスタンスaを作っています(6)。これでインスタンス「a」を操作することで、Sankakuクラスのメソッドにアクセスできるようになるわけです。
 ところが、このサンプルは大きな問題点を抱えています。それは、(3)で宣言したフィールドのアクセス指定子として「public」を指定していることです。publicという単語から想像が付くと思いますが、こう指定するとアクセスにまったく制限がなくなり、すべてのクラスから自由にアクセスできるようになります。先ほど、すべての情報をクラスの外部からアクセスできないようにするのもどうかと言いましたが、この情報に関しては別に自由にアクセスできるようにする必要ありません。クラスはできるだけ「独立」にするという原則を安直に崩すのは慎むべきです。しかもすべてのクラスから参照可能にすると、ほかのクラスから不用意にアクセスされる可能性があるので、バグを生む要因にもなりかねません。
 そこで、ここでは二つのフィールドを「private」にするするほうがよいでしょう。こうすると、そのフィールドを持つクラスの中からのみ参照可能になります。ただこのサンプルの場合、このままではフィールドを別途用意する必要があります。これらのことを踏まえてリスト1のコードを変更すると、リスト2のようになります。teihenとtakasaの値は
SetInfoメソッドを使って設定できます。

 プログラム・コードをすっきりさせるには、まずクラスとして切り分けるのが基本です。そして、クラスの中のデータや関数をどう外に見せるかを決めました(これがカプセル化です)。個々のクラスをどうするかに関しては、とりあえずこれでOKです。
 しかし、これだけでいいのだろうかという気がしませんか?ここまでのところ、切り分けられたクラスどうしの”関係”はまったく定義されていません。単に互いにメソッドを呼び出しあうだけの間柄です。何か不自然ですね。やはり、クラス同士を関係付ける仕掛けがあるべきだと思うでしょう。
 人間にとって、もっとも基本的だと思える関係は「親子(あるいは上位-下位)」の関係です。たとえば、筆者は「日経ソフトウェア」に属しています。つまり日経ソフトウェアと筆者は「日経ソフトウェア=親」「筆者=子」の関係にあります。一方、日経ソフトウェアは「日経BP社」に属しています。つまり「日経BP社=親」「日経ソフトウェア=子」という関係だって成り立つわけです。
 このように世の中の物事のほとんどは、何らかの形で親子関係を成しています。だったら、クラス同士の関係を表すのにも適しているはずです。オブジェクト指向でこのような親子関係を実現する機能を「継承(インヘリタンス)」と呼びます。
 継承を使うと、既存のクラス(つまり親のクラス)の機能を新しいクラス(つまり子のクラス)に引き継ぐことができます。つまり親クラスで定義されたフィールドやメソッドは、子クラスでも何も定義しないでそのまま使うことができるのです。もちろん子クラスで、継承した機能の一部を改変したり、別に独自のフィールドやメソッドを追加することも可能です。こうして作成した子クラスは、確かに親クラスの下位と呼べる存在になるわけですね。
 この継承は、さまざまな面で役に立ちます。例えばいくつかのクラスで共通したフィールドやメソッドがある場合、それらを親クラスとしてまとめてしまい、各クラスがそこから継承する形にするという手があります。こうすれば、各クラスは自分特有のフィールドやメソッドだけを持てばいいのでスリムにないます(図6)。また、ソフトの再利用も継承を使うと効率よくできます。クラスから継承して新たなクラスを作成すればよいのです。継承は、オブジェクト指向プログラミングのメリットを得るために不可欠な存在と言えるでしょう。
 では実際に、継承の例を見てみましょう。Javaでは親クラスをスーパークラス、子クラスをサブクラスと呼びます*9。先ほどのSankakuクラスをスーパークラスとして、三角すいを表すSankakusuiサブクラスを新たに作ってみます。このSankakuクラスはすでに、底辺と高さを表すフィールド、これらのデータを設定するSetInfoメソッド、面積を求めるGetMensekiメソッドを持っています。もし新しく作るSankakusuiクラスで三角すいの体積を求める機能を付けるとしたら、あと何の情報が必要なのでしょうか。そう、立体での高さを表す値(ここではz)ですね。「三角形の底面の面積*z/3」が三角すいの体積を求める公式です。これをJavaで記述すると、リスト3になります*10
 (1)がスーパークラスのSankakuクラス、(2)がサブクラスのSankakusuiクラスです。Javaではサブクラスを作る場合、サブクラス名のあとに「extendsスーパークラス名」を付けます*11。これで、スーパークラスSankakuのフィールドやメソッド(x,y,SetInfo,GetMenseki)を利用できるようになりました。
 次に、Sankakusuiクラスに必要なフィールドとメソッドを実装していきます。ここではフィールドとして立体での高さを表すz(3)、メソッドとしてzに値を格納するSetInfo(4)と体積を求めるGetMensekiメソッド(5)をそれぞれ実装しています。(5)でスーパークラスであるSankakuクラスのGetMensekiメソッドを使っていることに注目してください。
 ちなみにSankakuクラスのフィールドx,yに対しては、いくらサブクラスと言えどもSankakusuiクラスから直接アクセスすることはできません(図7)。このフィールドはprivateで宣言されているためです。もしサブクラスから直接スーパークラスのフィールドにアクセスしたいなら、「protected」で宣言してください。こうすれば、スーパークラスとサブクラス以外からはアクセスするのを防ぎ、スーパークラスとサブクラスからはアクセスすることが可能になります。

●継承 : 関係の基本は「親子」

*9 C++ではスーパークラスを基底クラス、サブクラスを派生クラスと呼びます。
*10 リスト3のSankakuクラスはリスト2のteihenを「x」に、takasaを「y」に変更しているだけです。
*11 C++では、サブクラス名のあとに「コロン(:)+スーパークラス名」と記述します。VBの場合、JavaやC++のような継承はできません。詳しくはPart2のカコミ記事(80〜81ページ)を参照してください。
*12 このほか、オーバーロード(overload)もポリモ-フィズムの例として挙げる人もいます。オーバーロードは、一つのクラス内に名称は同じ内容が異なるメソッドを定義することを指します。同じクラスで、三角形の面積を求めるメソッド「Menseki(int hankei)」を定義する、といった具合です。このように引数の型や個数は異なる必要があります。Javaではメソッドのオーバーロードのみ可能ですが、C++では演算子のオーバーロードもできます。
 ここまでの三つのキーワードは、オブジェクトの「切り分け」「見せ方」「関係」に関するものでした。もう一つは・・・と来たら、「振る舞い」になるでしょう。それが「ポリモ-フィズム(polymorphism)」です。
 ポリモ-フィズムといきなり言われるとさっぱり意味がわかりませんが、日本語で「多態性」「多相性」などと訳されます。これで少しはイメージがわくかもしれません。要は、オブジェクトの状態や振る舞いが「状況に応じて変わるようにすること」を指します。
 何かこれまでのクラスや継承などと比べるとちょっと特殊な機能のような気がしますが、そんなことはありません。いまこれを読んでるみなさんだって,、友だちのAさんと会うときと、後輩のBさんあるいは大先輩のCさんと会うときでは、話し方や態度が変わるでしょう。また、コーヒー屋で「一杯ください」と頼んだ場合では、出てくるものが(ほとんどの場合)違うはずです。このように「だれから依頼を受けたか/だれに依頼しているか」に応じて、自分の状態/受け取る結果が変わるというのは、ごく自然なことなのです。逆に、常に同じ状態/結果であるほうがよっぽど不自然です。
 オブジェクト指向でポリモ-フィズムを実現する機能の代表例はオーバーライド(override)です*12。オーバーライドとは、スーパークラスが持つメソッドと名前は同じで処理が異なるメソッドを、サブクラス側で実装することを指します。リスト4がその例です。
 ここでは四つのクラスが登場しています。犬を表す「Dog」がスーパークラスです。このDogクラスを継承して、チワワ犬を表す「Chihuahua」とセントバーナード犬を表す「SaintBernard」という二つのサブクラスを定義しています。もう一つ、リスト4の後ろのほうにあるRunTestは、この三つのクラスのインスタンスを作って実行するクラスです。
 このリスト4でbackメソッドに注目してください。Dogクラスでは「ワンワン」を返すbarkメソッドを定義しています。DogクラスのサブクラスであるSaintBernardは、このbarkメソッドをそのまま使います。ところがChihuahuaクラスを見ると、改めて「キャンキャン」を返すbarkメソッドを定義しているのがわかります。これがオーバーライドです。
 その結果、プログラムを実行するとどうなるかは明らかでしょう。SaitBernardクラスのメソッドをそのまま使っているからです。ところがChihuahuaクラスのインスタンスである「ハナ」は「キャンキャン」と返しています。Chihuahuaクラスでオーバーライドしたbarkメソッドを使っているためです。
 このようにポリモ-フィズムによって、同じメソッドを呼んでもクラスによって振る舞いが変わるようにできるのです。この場合なら、「ほえろ!」と命令したときに片方が「ワンワン」、もう片方が「キャンキャン」とほえることに相当するわけです。クラスの利用者にとっては、スーパークラスやサブクラスで実装されているメソッドの中身が異なっているかどうかを意識せずに同じように利用できるという利点があります。

●ポリモ-フィズム : オブジェクトは「変わる」

図7 ●スーパークラスのメンバーをprivateで宣言すると、サブクラスからはアクセスできない
Sankakuクラス(サブクラス
×
protected
public
Sankakuクラス(スーパークラス
private
リスト3 ●継承を利用した例。SankakuクラスはSankakusuiクラス継承している
 public class Sankaku {  --------------------------(1)
   private double teihen;                      ↑
   private double takasa;

   public Sankaku() {
    x = a;
    y = b;
   }

   public double getMenseki(){
    return x * y / 2;
   }                                  ↓
 }  -------------------------------------------(1)

 public class Sankakusui extends Sankaku{ ----------(2)
   private double z; -----------(3)           ↑

   public void SetInfo2(double c) { --------(4)
    z=c; -------------------------------(4)
   } -----------------------------------(4)

   public double GetTaiseki() { -----------(5)
    return GetMenseki()*z/3;  -----------(5)
   } -----------------------------------(5)    ↓
 } ---------------------------------------------(2)

 public class RunTest{

   public static void main(string[ ] args){
    Sankakusui Mys = new Sankakusui();
    Mys.SetInfo (10,20);
    Mys.SetInfo (30);
    System.out.println(Mys.getMenseki());
   }
 }
 public class SaintBernard extends Dog {
   public SaintBernard () {
     type = ”セントバーナード”;
   }
 }

 public class RunTest {
   public static void main(String[ ] args) {
    SaintBernard taro = new SaintBernard();
    taro.setName(”タロ”);

    SaintBernard jiro = new SaintBernard();
    taro.setName(”ジロ”);

    SaintBernard hana = new SaintBernard();
    taro.setName(”ハナ”);

    Dog.dogs[ ] = {taro,jiro,hana };

    for (int i = 0 ; i <= 2 ; i++) {
      System.out.println(dogs[ i ].getType());                 System.out.println("("+dogs[ i ].getType()+")");
      System.out.println("「"+dogs[ i ].bark()+"」");
    }
   }
 }
リスト4 ●オーバーライドの例。barkメソッドの鳴き声に注目
 public class Dog {
   Strig name;
   String type;

   public void setName(String n) {
     name = n;
   }

   public String getName(){
    return name;
   }

   public String bark(){
    return type;
   }
 }

 public class Chihuahua extends Dog {
   public Chihuahua () {
     type = ”チワワ”;
   }

   public String bark() {
     return ”キャンキャン!”;
   }
 }