Javaコラム Javaエンジニアのためのお役立ちコラム

そもそもJavaの継承とは?Javaを使いこなすために継承を理解しよう!

2020年10月27日
SE
Javaの継承とはどのようなことを意味するのでしょうか。
PM
継承とは簡単に言えば親子関係を作ることです。

Javaの継承とは?


Javaのプログラムは全てクラスをベースにして記述されます。そしてそのクラスは継承ができます。継承とは簡単に言えば親子関係を作ることです。

単純な例で説明しましょう。以下の生き物を表すクラスがあるとします。

class Ikimono {
public String name;

public void dispName() {
System.out.println(“”私は””+name+””です。””);
}
}

人間は生き物の一種です。Ikimonoの子クラス、Ningenを作ります。

class Ningen extends Ikimono {
}

extends IkimonoはNingenクラスがIkimonoクラスを継承しているという意味です。これがクラスの継承なのです。

継承したクラスを利用する

それではNingenクラスを使用してみましょう。以下のJavaサンプルをご覧ください。Javaのプログラムはmainメソッドから起動しますが、そのmainメソッドもこのようにクラスに属しています。

public class MainClass {
public static void main(String[] args) {
Ningen n = new Ningen();
n.name = “”人間””;
n.dispName();
}
}

子クラスは親クラスの機能を利用できる

Ningenクラスをnewで生成していますが、NingenクラスにはnameやdispNameは記述されておらずからっぽです。それなのに利用できるのは、親のIkimonoクラスにそれがあるからです。継承することで、子クラスは親クラスの機能を利用できるということですね。

実行すると以下のように表示されます。

私は人間です。

子クラスの継承もできるが親に持てるクラスは1つだけ

なお、以下のように子クラスをさらに継承することもできます。ただしJavaのクラスにおいて継承できるクラスは1つです。他の言語、例えばC++は多重継承ができますが、Javaはシンプルにするために親クラスは1つだけになっています。

class Shinjinrui extends Ningen {
}

ただしJavaにはクラスとは別にインターフェイスと言う機能があります。インターフェイスは以下のように複数継承できます。なおインターフェイスの場合は継承と言わずに実装と言います。

interface Itest1 {
}

interface Itest2 {
}

class Ningen extends Ikimono implements Itest1,Itest2 {
}

この記事ではインターフェイスの説明は省きますが、そちらについても是非調べてみてください。

クラスのフィールドには直接アクセスしない

上のサンプルではIkimonoクラスのnameにMainメソッドで直接アクセスしていますが、Javaではこのようにクラスのフィールドに直接アクセスすることは避けます。Ikimonoクラスを以下のように修正しましょう。

class Ikimono {
private String name;

public void setName(String str) {
if (str == null) str = “”””;
name = str;
}

public void dispName() {
System.out.println(“”私は””+name+””です。””);
}
}

フィールドアクセス用のメソッドを作るとできることが広がる

Ikimonoクラスのnameフィールドをprivateにしました。これで外部からアクセスできなくなります。その代わりにpublicのsetNameメソッドでnameを設定するようにしました。

setNameでは渡された文字列がnullだった場合は空文字を入れています。メソッドでアクセスすることでこのようなチェック処理を入れたり、ログを出力したりといったことができるのです。

あとはmainメソッドのnameにアクセスしている箇所を以下のように修正すれば、以前と同じように動作します。

n.setName(“”人間””);

オーバーライドを使ってみよう

Javaにはオーバーライドという親のメソッドを同名で上書きする機能があります。Ningenを以下のように直してみましょう。

class Ningen extends Ikimono {
public void dispName() {
System.out.println(“”私は人間の””+name+””です。””);
}
}

このように直すとnameでエラーが出てしまいます。それは親のnameがprivateなために子クラスでアクセスできないからです。そこで親のIkimonoクラスのnameを以下のように直してください。

protected String name;

オーバーライドで処理を差し替えられる

protectedはクラスの外部からアクセスできませんが、子クラスからであればアクセスできます。今回のケースにぴったりですね。これでエラーが出なくなります。

あとはmainメソッドを以下のようにすれば、

n.setName(“”太郎””);

以下のような実行結果になります。子クラスのNingenのdispNameが呼び出されていますね。

私は人間の太郎です。

オーバーライドの真価は?

ここまでではまだオーバーライドの利点はあまりわからないと思います。そこでもう1つ、以下のクラスを追加しましょう。

class Neko extends Ikimono {
public void dispName() {
System.out.println(“”私は猫の””+name+””ですニャ。””);
}
}

そしてmainメソッドを以下のように直してください。

public static void main(String[] args) {
Ikimono[] ik = new Ikimono[2];
ik[0] = new Ningen();
ik[0].setName(“”太郎””);
ik[1] = new Neko();
ik[1].setName(“”タマ””);

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

オーバーライドでポリモーフィズムを実現

NingenやNekoではなくIkimono型の配列に、NingenとNekoをnewしています。そしてループ処理でdispNameを呼び出しています。結果は以下のようになります。

私は人間の太郎です。
私は猫のタマですニャ。

なんと、Ikimono型で呼び出しているのに、それぞれnewしたクラスのdispNameが呼ばれています。これをポリモーフィズム(多態)と呼びます。非常に役に立つ機能で、Javaが普及した一因となっています。

親クラスをnewしないのであれば抽象クラスにしよう

このサンプルでさらにIkimonoクラスを継承する小クラスを増やしていくと、Ikimonoクラス自体はnewされることがなくなり、テンプレートのような抽象的な存在になっていきます。

そこで以下のようにIkimonoクラスの宣言にabstractを追加しましょう。これでIkimonoは抽象クラスになります。

abstract class Ikimono {

これで以下のようにIkimonoをnewしようとしてもエラーになります。Ikimonoクラスの意義が明確になって間違いもなくなりますね。

Ikimono ik = new Ikimono();

finalで継承やオーバーライドを防止できる

なおNingenやNekoをさらに継承させるのを止めたいという場合は、以下のようにクラス宣言のfinalをつけます。これで継承できなくなります。

final class Ningen extends Ikimono {

メソッドに付けた場合はオーバーライドができなくなります。

final public void dispName() {

SE
Javeの継承にはさまざまなメリットがあるのですね。
PM
状況によっては継承させないほうが良い場合もありますので、継承をやめさせる設定方法も学んでおくと良いでしょう。

Javaを使いこなすには継承を理解しよう

Javaの継承について解説しましたが、ご理解頂けましたでしょうか。この記事で説明した抽象クラスをさらに発展させたのがインターフェイスです。是非そちらについても是非調べてみてくださいね。


Javaでのキャリアアップをお考えの方は、現在募集中の求人情報をご覧ください。

また、直接のエントリーも受け付けております。

エントリー(応募フォーム)