Java クラスの継承とポリモーフィズム。

Javaでは、クラスの継承やポリモーフィズムの機能を上手く使うと、プログラムを効率よく開発することができます。

クラスの継承とは、既存のクラスのフィールドやメソッドを利用して、新しいクラスを楽に作る仕組みです。

ポリモーフィズム(polymorphism)は多相性、多態性といわれることもあり、類似したクラスのメソッドの呼び出し方を共通にする仕組みです。

これらの機能を使うとどんなことができ、どんなメリットがあるのか、実際に試してみましょう。


【1】sample09 フォルダをフォルダごとコピーして、sample15 フォルダを作ります。

java-311.gif

*sample15 フォルダ内にコピーされたクラスファイルは削除して、ソースファイルだけにしてください。


【2】Person.java と PersonTest.java は変更して、Boy.java と Girl.java は新たに作成します。

最終的にsample15 フォルダの中は以下のようになります。
java-313.gif

*「\」はWindowsではエンマークのことです。

保存先 C:\java\sample15
ファイル名 Person.java

class Person {
  String name;
  int age;
  String address;

  Person(String _name, int _age, String _address) {
    name = _name;
    age = _age;
    address = _address;
  }

  void say(){
    System.out.println("私の名前は" + name + "です。年齢は"
    + age + "才で、住所は" + address + "です。");
  }

  void setName(String _name){
    name = _name;
  }

  void setAge(int _age){
    if (_age > 0) {
      age = _age;
    }else{
      age = 0;
    }
  }

  void setAddress(String _address){
    address = _address;
  }

  String getName(){
    return name;
  }

  int getAge(){
    return age;
  }

  String getAddress(){
    return address;
  }

}



保存先 C:\java\sample15
ファイル名 Boy.java

class Boy extends Person {

  Boy(String _name, int _age, String _address) {
    super(_name,_age,_address);
  }

  void say(){
    System.out.println("ぼく" + name + "。年齢は"
    + age + "才なんだ。" + address + "に住んでるんだよ。");
  }

}



保存先 C:\java\sample15
ファイル名 Girl.java

class Girl extends Person {

  Girl(String _name, int _age, String _address) {
    super(_name,_age,_address);
  }

  void say(){
    System.out.println("わたし" + name + "です。年齢は内緒("
    + age + ") " + address + "に住んでます。");
  }

}



保存先 C:\java\sample15
ファイル名 PersonTest.java

class PersonTest {
  public static void main(String[] args) {

    Person[] people = new Person[4];
    people[0] = new Person("太郎", 21, "東京都港区");
    people[1] = new Person("花子", 18, "北海道札幌市");
    people[2] = new Boy("次郎", 9, "福岡県福岡市");
    people[3] = new Girl("桃子", 8, "宮城県仙台市");

    System.out.println("----- say()メソッドで表示");

    for(int i = 0; i < people.length; i++){
      people[i].say();
    }

    System.out.println();
    System.out.println("-----セッターでデータを変更");

    people[2].setName("三郎");
    people[2].setAge(5);
    people[2].setAddress("沖縄県那覇市");
    people[3].setName("梅子");
    people[3].setAge(4);
    people[3].setAddress("徳島県徳島市");

    System.out.println();
    System.out.println("-----ゲッターでデータを取得して表示");

    for(int i = 0; i < people.length; i++){
      System.out.println(people[i].getName() + " "
        + people[i].getAge() + " " + people[i].getAddress() );
    }

  }
}



【3】コマンドプロンプトを起動して、カレントディレクトリを sample15 に切り替えます。

java-312.gif


【4】javac PersonTest.java と入力し、コンパイルします。

java-314.gif

コンパイルが成功すると sample15 フォルダの中にクラスファイルが4つ作成されます。

java-315.gif


【5】java PersonTest と入力し、プログラムを実行します。

java-318.gif


【6】プログラムの実行結果が表示されました。

java-316.gif


【解説】

今回の最大のポイントは、同じ方法で say() メソッドを呼び出していますが、
for(int i = 0; i < people.length; i++){
  people[i].say();
}

表示がインスタンスごとに変わるところです。
java-317.gif


(1)アクセス修飾子
Person、Boy、Girlクラスのフィールドとメソッドのアクセス修飾子を「指定なし」にしているので、同一クラス内、同一パッケージからアクセス可能となっています。

Personクラスのフィールドやメソッドを「指定なし」にしたのは、private にするとサブクラスが継承できないからです。クラスを継承させたい場合、スーパークラスのアクセス修飾子は、「指定なし」か「protected」にする必要があります。


(2)クラスの継承
まずクラスの書式の復習です。[]カッコは省略できることを表しています。これまでは [extends節] を省略していました。クラスの継承ではこの [extends節] を使います。extends の後に継承したいクラス名を書くだけです。

・正式形
[修飾子] class クラス名[extends節][implements節] {
  内容
}

・簡略形
class クラス名 {
  内容
}


(3)今回の例ではPersonクラスを継承して、Boy、Girlクラスを作成しています。この場合Personクラスをスーパークラス、Boy、Girlクラスをサブクラスといいます。

クラスを継承すると、スーパークラスで定義したフィールドやメソッドをサブクラスでは定義することなしに使うことができます。Boy、Girlクラスではフィールドを宣言していないのに使えていることに注目してください。

もちろんサブクラス側で再定義することもでき、その場合はサブクラス側で定義したものが優先されます。これをフィールドの隠蔽、メソッドのオーバーライドといいます。今回はsay()メソッドをオーバーライドすることで、インスタンスごとに表示を変えています。フィールドの隠蔽は行っていません。


(4)クラスの継承で注意する点として、コンストラクタだけは継承されませんので、サブクラス側で再定義しなければなりません。しかしsuperを使うと、1つ上のスーパークラスのフィールドやメソッドにアクセスできますので、サブクラスのコンストラクタを簡単に書くことができます。

以下はsuperを使い、スーパークラスの仮引数が2つあるコンストラクタを呼び出しています。Boyクラスのコンストラクタで受け取った値を、さらにsuperの実引数にしているところがポイントです。これでPersonクラスのコンストラクタが呼び出されます。

Boy(String _name, int _age, String _address) {
  super(_name,_age,_address);
}


(5)同型の変数
クラスのインスタンスは同型の変数で指し示すことができます。異なる型の変数では指し示すことができません。Personのインスタンスを指すにはPerson型の変数しか使えません。

しかしクラスが継承関係にある場合、スーパークラス型の変数でサブクラスのインスタンスも指すことができます。(操作できるということ)

以下の例では、Person型の変数を用意しておいて、new演算子のあとにそれぞれのクラスのコンストラクタを呼び出すことで、異なる型のインスタンスをPerson型で指すようにしています。

Person[] people = new Person[4];
people[0] = new Person("太郎", 21, "東京都港区");
people[1] = new Person("花子", 18, "北海道札幌市");
people[2] = new Boy("次郎", 9, "福岡県福岡市");
people[3] = new Girl("桃子", 8, "宮城県仙台市");


*ただしスーパークラスにはなく、サブクラスで独自に作ったフィールドやメソッドは、スーパークラス型の変数では利用できません。


今回はまず継承関係のクラスを作り、スーパークラス型の変数でインスタンスを操作することで、「メソッドの呼び出し方を共通」にしていたのです。このようにポリモーフィズムを使うとサブクラスの種類が増えても呼び出し方を変更する必要がないので、プログラムのメンテナンスが楽になるメリットがあります。

クラス継承のメリットは、既存のクラスのフィールドやメソッドを利用して、新しいクラスを楽に作る他に、ポリモーフィズムを使えるようになることもあります。


スポンサードリンク

スポンサードリンク






Java初心者入門講座TOPへ