はじめに
継承は、1つのクラスを全て引き継いで新しいクラスを作成する方法です。既にあるクラスへ属性や機能を継ぎ足して新しいクラスを作成する方法です。すでにあるクラスに属性や機能を継ぎ足して新しいクラスを作る差分プログラミングを可能にします。この章では継承の仕組みを学習します。
目次
- 継承
- クラスの階層
- protected修飾子
- 参照型の自動型変換
- ダウンキャスト
- instanceof演算子
- 引数における参照型の自動型変換
- 戻り値における参照型の自動型変換
- 章のまとめ
目標
継承を使ったクラスを作成できる様にすること。
継承
継承は、オブジェクトの設計図であるクラスを再利用するための技術です。
文字通り、既存のクラスを引き継いだ上で、さらに機能をつけて加えたり、あるいは一部の機能を変えたりして、新しいクラスを作ることができます。

例えば、既に上記のような社員情報を管理するEmployeeクラスが存在していたとします。その後、社員情報に加えて、営業情報も追加した新しいクラスを作成したいと依頼があった場合、一からクラスを新しく定義し直すと効率が悪いです。そんな時に継承を利用します。
例題(継承)
実際に継承を利用したクラスを作成してみましょう。
今回は、Employeeクラスというクラスを作成します。Employeeクラスは、属性として社員名前と社員IDの情報を保持し、操作として社員情報を表示することもできるクラスです。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | Employee |
package chapter8; |
Employeeクラスを継承し、営業情報も追加したクラス(SalesEmpクラス)を作成します。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | SalesEmp |
| 継承 | Employee |
package chapter8; |
実行するためのクラス(EmpExecクラス)を作成します。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | EmpExec |
package chapter8; |
コンパイル例:> javac chapter8¥Employee.java
> javac chapter8¥SalesEmp.java
> javac chapter8¥EmpExec.java
実行例:> java chapter8.EmpExec
営業部番号:5000
個人売上高120000000
継承の定義方法
クラスを継承するには、extendsキーワードを使用します。
extendsキーワードの構文は以下です。

SalesEmpクラスを宣言する際に付与されているextends Employeeが継承を意味します。今回はEmployeeクラスを継承するという意味になります。
SalesEmpクラスはEmployeeクラスに定義されているメンバ変数やメソッドを引き継いでいます。
継承を利用した場合extendsキーワードで指定されているクラス(継承元のクラス)をスーパークラスといいます。
スーパークラスをを継承して作成する新しいクラスをサブクラスといいます。
上記の場合、SalesEmpクラスがスーパークラス、Employeeクラスがサブクラスです。
サブクラスのインスタンス化
Java言語の規約では、サブクラスのコンストラクタは、最初にスーパークラスのコンストラクタを実行しなければならないと決められています。

スーパークラスのコンストラクタを呼び出すためにはsuperキーワードを利用します。
[スーパクラスのコンストラスタをサブクラスから呼び出す場合]super(引数リスト);
今回の場合、スーパークラスであるEmployeeクラスのコンストラクタが以下のように定義されています。
public Employee(String empName, int empId){ |
サブクラスのコンストラクタは、最初にスーパークラスのコンストラクタを実行しなければならないので、スーパークラスのコンストラクタの定義に合わせて呼び出しを行わなければなりません。
今回の場合、サブクラスであるSalesEmpクラスのコンストラクタ内で、最初にEmployeeクラスのコンストラクタを呼び出す必要があります。そのため、Employeeクラスではコンストラクタを以下のように定義します。
public SalesEmp(String empName, int empId, int salesId, int salesVolume){ |
スーパークラスのコンストラクタが明示的に定義されている場合は、サブクラスのコンストラクタ内で必ず一番最初にスーパークラスのコンストラクタの呼び出しを定義しておかないと、コンパイルエラーになりますので注意して下さい。
スーパークラスのメンバ変数の呼び出し
サブクラス内でスーパクラスのメンバ変数を利用するためには、スーパークラスに定義してあるメンバ変数名をそのまま指定します。
先ほど作成しました、EmployeeクラスとSalesEmpクラスを以下のように修正してみましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | Employee |
package chapter8; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | SalesEmp |
| 継承 | Employee |
package chapter8; |
コンパイル例:> javac chapter8¥Employee.java
> javac chapter8¥SalesEmp.java
実行例:> java chapter8.EmpExec
入社日:2019/10/01
誕生日:2000/01/01
また、スーパークラスで定義したメンバ変数と同じ名前の変数をサブクラスのメンバ変数として定義することも可能です。
そうした場合、サブクラス内でスーパークラスのメンバ変数を呼び出したい場合は以下のように定義します。
[スーパークラスで定義しているメンバ変数を、サブクラス内で利用したい場合]super.スーパークラスで定義したメンバ変数名
SalesEmpクラスを以下のように修正してみましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | SalesEmp |
| 継承 | Employee |
package chapter8; |
コンパイル例:> javac chapter8¥Employee.java
> javac chapter8¥SalesEmp.java
実行例:> java chapter8.EmpExec
誕生日(スーパークラス):2000/01/01
誕生日(サブクラス):1980/01/01
サブクラス内で定義しているメンバ変数と、スーパークラスで定義しているメンバ変数が同じ名前の場合は、superキーワードを指定すると、スーパークラスで定義しているメンバ変数を利用することができます。

スーパークラスのメンバメソッドの呼びだし
サブクラス内でスーパークラスのメンバメソッドを呼び出したい場合、スーパクラスのメソッド名を指定します。
SalesEmpクラスの以下の箇所を修正し、実行してみましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | SalesEmp |
| 継承 | Employee |
package chapter8; |
コンパイル例:> javac chapter8¥SalesEmp.java
実行例:> java chapter8.EmpExec
社員名:福山雅治
社員番号1000
継承とis-a関係
is-a関係とは、「A is a B」という関係を表す表現技法のことです。
ある2つのオブジェクトを、Aはサブクラス、Bはスーパークラスとして当てはめた時に「A is a B」という表現が成りたつと、AとBは継承していると証明することができます。
先ほど作成した、EmployeeクラスとSalesEmpクラスをis-a関係で表現すると以下になります。
SalesEmpクラスはEmployeeクラスの一種です。 |
上記、is-a関係でSalesEmpクラスとEmployeeクラスは成立する為、継承関係であることが証明できます。
継承されないもの
サブクラスへ継承されるものは、オブジェクトです。オブジェクトの中に存在しない以下の2つは、継承の対象ではありません。
コンストラクタ- 静的メンバ(
static修飾子が付加されたメンバ)
例題(static修飾子が付加されたメンバ)
static修飾子が付加されたメンバは、以下のようにアクセスも可能ですので注意して下さい。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | AAAA |
package chapter8; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | BBBB |
| 継承 | AAAA |
package chapter8; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | Exec |
package chapter8; |
コンパイル例:> javac chapter8¥AAAA.java
> javac chapter8¥BBBB.java
> javac chapter8¥Exec.java
実行例:> java chapter8.Exec
20
アクセスが制限されたメンバ
static修飾子が付加された変数はクラス変数で、インスタンス化しなくても「クラス名.変数名」で利用ができます。
インスタンス化し、参照型の変数を通してもアクセスもできますが、本来は「クラス名.変数名」でアクセスすることが一般的です。
また、次の修飾子によって、アクセスが制限されたメンバも継承できません。
final修飾子が付加されたクラスprivate修飾子されたメンバfinal修飾子は「変更ができない」ことを表す修飾子です。クラスに付与すると、継承できないクラスになります。クラス以外にもメソッドやメンバ変数へfinal修飾子を付与することができます。final修飾子が付与されたメンバ変数は、初期設定した内容を変更できなくなります。final修飾子が付与されたメソッドは、オーバーライド(後述で説明)出来なくなります。
private修飾子が付与されているメンバ(メンバ変数やメソッド)は、クラス内のみアクセス可能な修飾子です。
例題(アクセスが制限されたメンバ)
先ほど作成した
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | AAAA |
package chapter8; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | BBBB |
| 継承 | AAAA |
package chapter8; |
コンパイル例:> javac chapter8¥AAAA.java
> javac chapter8¥BBBB.java
chapter8/BBBB.java:7: エラー: final AAAAからは継承できません
public class BBBB extends AAAA {
^
エラー1個
クラスの階層
継承関係を図示したものを、継承ツリーといいます。Java言語では、Objectクラスを起源として階層構造で継承しています。
すべてのクラスはObjectクラスのサブクラスです。クラス宣言に何も継承されていない場合は、コンパイラが「extends Object」を自動的に挿入します。

単一継承

1つのクラスを継承することを単一継承といいます。逆に2つ以上のクラスを同時に継承することを多重継承といいます。Java言語は単一継承です。多重継承を行いたい場合は、インターフェースを利用します。
Objectクラスのメソッド
Objectクラスには、いくつかの基本的なメソッドが定義されています。これらは全てのオブジェクトに継承されるメソッドです。
Objectクラスのメソッド
| メソッド名 | 機能 |
|---|---|
| toString() | オブジェクトの文字列表現を返す |
| clone() | このオブジェクトのコピーを作成して返す |
| equals(Object obj) | このオブジェクトと他のオブジェクトが等しいかどうか示す |
| hashCode() | オブジェクトのハッシュコードを返す |
| finalize() | ガベージコレクション用 |
| getClass() | このオブジェクトの実行時クラスを返す |
| notify() | マルチスレッド処理用。待機中のスレッドを一つ再開する。 |
| notifyAll() | マルチスレッド処理用。待機中のスレッドを全て再開する。 |
| wait() | マルチスレッド処理用。スレッドを待機させる。 |
| wait(timeout) | マルチスレッド処理用。制限時間付きでスレッドを待機させる。 |
| wait(timeout , nanos) | マルチスレッド処理用。制限時間付きでスレッドを待機させる。 |
Objectクラスは全てのクラスに必要の為、明示的に継承しなくてもコンパイル時に自動的に継承される仕組みになっています。つまり全てのクラスは、暗黙のうちにObjectクラスを継承したクラスなのです。
継承によるデフォルトコンストラクタ
サブクラスのコンストラクタでは、最初にスーパークラスのコンストラクタを実行して、スーパークラスのオブジェクトを初期化する必要がありました。
サブクラスのコンストラクタ内に、スーパクラスのコンストラクタの呼び出しが明示的に定義されていない場合、スーパークラスのコンストラクタを呼び出すためのデフォルトコンストラクタ(super();)が、コンパイラによって自動的に挿入されます。

例題(継承によるデフォルトコンストラクタ)
それでは、以下のConstructorChainクラスを作成し、実行結果を確認してみてください。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Data | |
| クラス名 | DataA | Dataクラスを継承 |
| クラス名 | DataB | DataAクラスを継承 |
| クラス名 | ConstructorChainExec | |
| ファイル名 | ConstructorChainExec.java |
package chapter8; |
コンパイル例:> javac chapter8¥ConstructorChainExec.java
実行例:> java chapter8.ConstructorChainExec
Data
DataA
DataB
;
上記の場合、サブクラスには、スーパークラスのコンストラクタの呼び出しが明示的にされていない為、コンパイルする際に暗黙の内にsuper()が挿入されます。
その為、Testクラスで「new DataB()」を実行すると、まずDataAクラスのコンストラクタが起動されます。
/** |
しかしながら、DataAクラスはDataクラスを継承しているので、Dataクラスのコンストラクタが起動します。
/** |
Dataクラスではextendsキーワードが指定されていないので、明示的には何も継承されていませんが、明示的に継承されていない場合には、暗黙的にObjectクラスのコンストラクタが継承されます。その為、最初に実行されるコンストラクタはObjectクラスのコンストラクタが実行されます。
/**
* Dataのコンストラクタ
*/
public Data(){
super(); //コンパイラによって暗黙の内に挿入される(Objectクラスのコンストラクタの呼び出し)
System.out.println("Data");
}
その為、Dataクラスのコンストラクタ、DataAクラスのコンストラクタ、DataBクラスのコンストラクタが実行され、以下のようにコンソールへ出力されます。
Data |
protected修飾子
今までpublic、private、デフォルトアクセスについて解説してきましたが、もう一つアクセスするための修飾子があります。それはprotected修飾子です。protected修飾子は、継承と関わりがある修飾子です。
protected修飾子の役割
protected修飾子の役割は以下の2つです。
サブクラスからアクセスできるようにする(別のパッケージからでも、継承していればアクセスすることができる)同じパッケージのクラスからアクセスできるようにする(デフォルト修飾子と同じ役割)
protected修飾子はデフォルトアクセス修飾子に、サブクラスの範囲が追加した修飾子です。

protected修飾子は、サブクラスを設計しやすくするために設けられた修飾子で、デフォルトアクセス修飾子よりもカプセル化をさらに弱める効果があります。
例題(別パッケージのクラスを継承している場合)
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8A |
| クラス名 | C |
package chapter8A; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8B |
| クラス名 | D |
| 継承 | chapter8A.C |
package chapter8B; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8B |
| クラス名 | ExecCD |
package chapter8B; |
コンパイル例:> javac chapter8A¥C.java
> javac chapter8B¥D.java
> javac chapter8B¥ExecCD.java
実行例:> java chapter8B.ExecCD
1.0
Cクラスです。
protected修飾子が付加されているメンバは、別のパッケージからでも、継承していればアクセスすることができます。
例題(同じパッケージのクラスを継承している場合)
新たに以下のクラスを作成し、確認してみましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | A |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | B | |
| 継承 | chapter8.A |
package chapter8; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter8 |
| クラス名 | ExecAB |
package chapter8; |
コンパイル例:> javac chapter8¥A.java
> javac chapter8¥B.java
> javac chapter8¥ExecAB.java
実行例:> java chapter8.ExecAB
1.0
Aクラスです
protected修飾子を付加したメンバは、同じパッケージからもアクセスできます。
(デフォルト修飾子と同じ役割を果たします。)
アクセス修飾子のまとめ
| 修飾子 | 意味 |
|---|---|
| public | パッケージを問わず、どのクラスからでも直接アクセスが可能 |
| protected | 同一パッケージの外部クラス、またはしたサブクラスからであればアクセスが可能 |
| 修飾子なし | 同一パッケージの外部クラスからであればアクセス可能 |
| private | 外部クラスからのアクセスはできず、同一クラス内のメソッドからのみアクセス可能 |
アクセス修飾子の適用場所
アクセス修飾子はクラス、コンストラクタ、クラスメンバ(メンバ変数、メソッド)、インターフェースにつけることができます。
(ただし、classにはprivateとprotectedは適用できません。またインターフェースはpublic以外は適用できません。)
| アクセス修飾子 | class | コンストラクタ | メンバ変数 | メソッド | インターフェース |
|---|---|---|---|---|---|
| public | ● | ● | ● | ● | ● |
| protected | × | ● | ● | ● | × |
| 修飾子なし | ● | ● | ● | ● | × |
| private | × | ● | ● | ● | × |
参照型の自動型変換
基本データ型では自動型変換やキャストすることで、型は違っていても代入することができる仕組みがありました。オブジェクトを扱う参照型も同様な仕組みがあります。
ここでは参照型の自動型変換について学習します。
参照型の自動型変換の条件
参照型の自動型変換をおこなう場合、次のような条件があります。
- 同じ継承ツリーの中に限る
- 継承ツリーの矢印の向きにのみ可能

例題(参照型の自動型変換)
以下、Company←Employee←SalesEmpという同じ継承ツリーにあるクラスで、参照をスーパークラス(親クラス)の変数に代入して使用できるかどうかを確認している例題です。
以下のクラスを作成し、実行結果を確認してみましょう。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Company |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Employee | |
| 継承 | Company |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | SalesEmp | |
| 継承 | Employee |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Exec |
package chapter8; |
コンパイル例:> javac chapter¥SalesEmp.java
> javac chapter8¥Employee.java
> javac chapter8¥SalesEmp.java
> javac chapter8¥Exec.java
実行例:> java chapter8.Exec
-----sの変数範囲でアクセス------
SalesEmp class
Employee class
Company class
-----eの変数範囲でアクセス------
Employee class
Company class
-----cの変数範囲でアクセス------
Company class
上記、SalesEmpクラスのオブジェクトを一つだけ作成し、その参照をeとcといった、スーパクラスの変数へ代入しています。
eとcはそれぞれのクラスの該当部分を参照し、empDisp()メソッドやcomDisp()メソッドを実行できていることがわかります。

尚、Execクラスへ以下を追記すると、コンパイルエラーになります。
e.salesDisp(); |

参照範囲外のメンバへアクセスはできない仕組みになってます。
ダウンキャスト
通常、継承ツリーの矢印と逆向きに代入しようとすると、コンパイルエラーが発生します。

コンパイルエラーを発生させずに代入するには、ダウンキャストをおこないます。
ダウンキャストの定義方法
ダウンキャストするためには、括弧を使用して明示的に型を指定します。
サブクラス型 変数名 = (サブクラス型)スーパークラス型の参照 |
例題(ダウンキャスト)
先ほど作成したExecクラスを以下のように修正してみましょう。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Exec |
package chapter8; |
コンパイル例:> javac chapter8¥Exec.java
chapter8/Exec.java:20: エラー: 不適合な型: EmployeeをSalesEmpに変換できません:
SalesEmp s1 = e; //Employee型の変数eを、SalesEmp型の変数s1へ代入するとコンパイルエラーが発生する
^
エラー1個
上記、スーパークラス(Employee)をサブクラス(SalesEmp)へ代入しようとしていて、コンパイルエラーが発生しています。
Execクラスを以下のように修正してください。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Exec |
package chapter8; |
コンパイル例:> javac chapter8¥Exec.java
実行例:> java chapter8.Exec
-----s1の変数範囲でアクセス------
SalesEmp class
Employee class
Company class
ダウンキャストをおこなうと、コンパイルエラーが発生せず実行する事ができます。

元々メモリ上に、SalesEmpオブジェクトが生成されているので、ダウンキャストしても参照範囲が一致する為、問題なく実行することができます。
ダウンキャストしても、メモリ上に作成されているオブジェクトがスーパークラスの場合は、実行時に例外が発生します。
Execクラスを以下のように修正してください。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Exec |
package chapter8; |
コンパイル例:> javac chapter8¥Exec.java
実行例:> java chapter8.Exec
Exception in thread "main" java.lang.ClassCastException: class chapter8.Employee cannot be cast to class chapter8.SalesEmp (chapter8.Employee and chapter8.SalesEmp are in unnamed module of loader 'app')
at chapter8.Exec.main(Exec.java:19)
メモリー上に作成されているオブジェクトはスーパークラスであるEmployeeオブジェクトです。しかしながら
s1の変数にはサブクラス型の参照が代入されています。オブジェクトのメンバを超えて参照することができる為、実行時例外(java.lang.ClassCastException)が発生します。

※ダウンキャストを行う際は、注意して定義してください。
instanceof演算子
参照型の変数が、どんな型のオブジェクトか確認したい場合、instanceof演算子を利用します。
instanceof演算子は以下のように利用します。変数 instanceof 型
変数が参照しているオブジェクトの型が、同じかあるいはそのサブクラスならtrueを返します。
例題(instanceof演算子)
以下クラスを作成し、実行結果を確認してみましょう。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Food |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Fruit | |
| 継承 | Food |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Apple | |
| 継承 | Fruit |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | AppleObjExec |
package chapter8; |
コンパイル例:> javac chapter8¥Food.java
> javac chapter8¥Fruit.java
> javac chapter8¥Apple.java
> javac chapter8¥AppleObjExec.java
実行例:> java chapter8.AppleObjExec
ダウンキャスト実行します
is-a関係とinstanceofの実行結果
is-a関係とは、継承を表す表現技法です。
X is a Z |
- XはZ型である
- XはZを継承している
- XはZの派生クラスである
- XはZのサブクラスである
instanceof演算子の結果がtrueの場合は、is-a関係が成立します。
先ほど作成しましたAppleObjExecクラスを修正し、実行結果を確認してみましょう。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | AppleObjExec |
package chapter8; |
コンパイル例:> javac chapter8¥Food.java
> javac chapter8¥Fruit.java
> javac chapter8¥Apple.java
> javac chapter8¥AppleObjExec.java
実行例:> java chapter8.AppleObjExec
-----Appleクラス-----
true
true
true
-----Fruitクラス-----
true
true
false
-----Foodクラス-----
true
false
false
上記の場合、変数appleはFoodクラスのサブクラスのサブクラスであり、Fruitクラスのサブクラス、Appleクラスである為、
全てtrueを返します。
変数fruitはFoodクラスのサブクラスであり、Fruitクラスである為、trueを返します。Appleクラスとの関係はスーパークラスにあたる為、falseを返します。
変数foodはFoodクラスの為、trueを返します。
引数における参照型の自動型変換
メソッドの引数(仮引数)が参照型の場合、メソッドを実行するときの引数(実引数)へ、サブクラスの引数を指定することができます。
例題(引数における参照型の自動型変換)
新たに、CookクラスとCookObjExecクラスを作成し、実行結果を確認してください。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | Cook |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | CookObjExec |
package chapter8; |
コンパイル例:> javac chapter8¥Cook.java
> javac chapter8¥CookObjExec.java
実行例:> java chapter8.CookObjExec
---Appleオブジェクトを実引数に指定---
Food class
---Fruitオブジェクトを実引数に指定---
Food class
Cookクラスのbakeメソッドは引数(仮引数)にFood型の参照が定義されています。
「cook.bake(apple);」では、Food型のサブクラスであるApple型の変数appleを引数(実引数)へ指定しています。
実行すると、サブクラスであるappleが自動型変換されて、スーパークラス型のfoodへ代入されます。
そしてFoodクラスのメソッドfoodDisp()メソッドが実行され、「Food class」とコンソール上に表示されます。
※「cook.bake(fruit);」も同様に自動変換され、「Food class」とコンソール上に表示されます。
戻り値における参照型の自動型変換
メソッドの戻り値が参照型の場合、戻り値型に指定されている型のサブクラスを返すことができます。
例題(戻り値における参照型の自動型変換)
新たに以下を作成し、確認してください。
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | FoodCheck |
package chapter8; |
| 項目 | 名前 | 備考 |
|---|---|---|
| プロジェクト | alj_study | |
| パッケージ | chapter8 | |
| クラス名 | FoodCheckExec |
package chapter8; |
FoodCheckクラスのget()メソッドは引数にint型の1を指定するとFood型のサブクラスのAppleオブジェクトを返します。
1以外を指定すると、Food型のサブクラスであるFruitオブジェクトを返します。上記の場合、「fch.get(1);」を指定しており、実行するとAppleオブジェクトが返されます。
まとめ
以下の要点をしっかり理解してから次の章へ進んでください。
継承
継承は、オブジェクトの設計図であるクラスを再利用するための技術である継承は、既存のクラスを引き継いだ上で、さらに機能をつけて加えたり、あるいは一部の機能を変えたりして、新しいクラスを作ることができる- クラスを継承するには、
extendsキーワードを使用する extendsキーワードの後に、継承したいクラス名を指定するextendsキーワードの後に指定したクラス(継承元)をスーパークラス(親クラス)という継承によって新たに作成するクラス(継承先)をサブクラス(子クラス)という- サブクラス(子クラス)の定義には、
スーパクラスに追加したい定義を追記する - extendsキーワードの後に指定できるクラスは1つのみである(
単一継承) - サブクラス(子クラス)は、スーパークラス(親クラス)のメンバ(フィールド)やメソッドを自分のものとして扱えることができる
superキーワードを利用すると、スーパークラスのメンバ(変数やメソッド)やコンストラクタを呼び出すことができる- サブクラスをインスタンス化すると、スーパークラス、サブクラスの順に生成される
- サブクラスのコンストラクタが呼ばれると、スーパクラスのコンストラクタが呼ばれる
- サブクラスのコンストラクタは、最初にスーパークラスのコンストラクタを実行しなければならない
- スーパークラスのコンストラクタの定義に合わせて呼び出しを行わなければならない
- スーパークラスのコンストラクタを呼び出す場合は「super(引数リスト);」と記載する
- サブクラス内でスーパークラスのメンバ変数を利用したい場合、スーパークラスのメンバ変数名がそのまま利用できる。
- スーパークラスのメンバ変数と同じ名前のメンバ変数をサブクラス内に定義することもできる
- 呼び出す場合には、superキーワードを利用する
- サブクラス内でスーパークラスのメンバメソッドを利用したい場合、スーパークラスのメンバメソッド名で利用できる。
- is-a関係とは、「A is a B」という関係を表す表現技法のこと
- Aがサブクラス、Bがスーパークラスとして当てはめた時、「A is a B」の文章が成り立つと継承関係であることが証明できる
- オブジェクト内に存在しないコンストラクタや静的メンバ(static修飾子)は継承されない
- final修飾子やprivate修飾子が付加されたメンバは継承されない
クラスの階層
- 継承関係を図示したものを、継承ツリーといい、Objectクラスを起源として継承している
- すべてのクラスはObjectクラスのサブクラスである
- クラス宣言に何も継承されていない場合は、コンパイラが「extends Object」を自動的に挿入する
- 1つのクラスを継承することを単一継承という
- 2つ以上のクラスを同時に継承することを多重継承という
- Javaは単一継承である
- 多重継承を行いたい場合は、インターフェースを利用する
- オブジェクトクラスには、いくつかの基本的なメソッドが定義されている
- Objectクラスで定義されているメソッドは、全てのオブジェクトへ継承されるメソッドである
- サブクラスのコンストラクタにスーパークラスのコンストラクタの呼び出しが定義されていない場合、コンパイラは、スーパークラスを呼び出すためのデフォルトコンストラクタ(super();)を暗黙の内に挿入する
- デフォルトコンストラクタのアクセス修飾子はクラスのアクセス修飾子と同じになる
- 継承では、サクブラスにおけるコンストラクタの呼び出しが次々とスーパークラスに波及する
- extendsを明示的に記述していないクラスは、Objectクラスを継承している
protected修飾子
- protected修飾子は、サブクラスを設計しやすくするために設けられた修飾子
- 同じパッケージのクラスからアクセスできるようにする(デフォルト修飾子と同じ役割)
- サブクラスからアクセスできるようにする(別のパッケージからでも、継承していればアクセスすることができる)
| アクセス修飾子 | class | コンストラクタ | メンバ変数 | メソッド | インターフェース |
|---|---|---|---|---|---|
| public | ● | ● | ● | ● | ● |
| protected | × | ● | ● | ● | × |
| 修飾子なし | ● | ● | ● | ● | × |
| private | × | ● | ● | ● | × |
参照型の自動型変換
- 基本データ型と同じように参照型でも
自動型変換される仕組みがある - 参照型の自動型変換対象は、
同じ継承ツリー内に限られる サブクラスのオブジェクトの参照は、スーパクラスの変数へ代入できる(自動型変換可能)参照型の変数が、オブジェクトへアクセスできる範囲(参照範囲)は、変数の型によって決まる- 自動型変換により代入されると、
スーパクラスで定義されているメンバ名の範囲で、サブクラスのオブジェクトへアクセス(参照)することができる - 自動型変換により代入されると、スーパクラスで定義されているメンバ名の
範囲外はアクセスすることができない(アクセス(参照)しようとするとコンパイルエラーが発生する)
ダウンキャスト
- 継承ツリーの矢印と
逆向きへ代入しようとすると、コンパイルエラーが発生する - 継承ツリーの矢印と
逆向きへプログラマが明示的に代入することをダウンキャストという ダウンキャストは、同じ継承ツリー内であれば、どんなクラスも変換可能- オブジェクトが元々サブクラスのオブジェクトであれば問題ないが、そうでない場合は
実行時例外が発生する可能性がある ダウンキャストするとコンパイルエラーにならない- 元からサブクラス型のオブジェクトを
参照していると、実行時例外は発生しない - 元からサブクラス型のオブジェクトを
参照していないと実行時例外(java.lang.ClassCastException)が発生し、停止する
instanceof演算子
instanceof演算子は、変数が参照しているオブジェクトの型を調べる演算子である- 変数が参照しているオブジェクトの型が、
同じかあるいはそのサブクラスならtrueを返す is-a関係とは、継承を表す表現技法であるinstanceof演算子の結果がtrueの場合、is-a関係が成立する
引数における参照型の自動型変換
- メソッドの
引数(仮引数)が参照型の場合、メソッドを実行するときの引数(実引数)へサブクラスの引数を指定することができる
戻り値における参照型の自動型変換
- メソッドの
戻り値が参照型の場合、戻り値型に指定されている型のサブクラスを返すことができる