Javaの「継承」をざっくりまとめてみた[Java入門]
はじめに
こんにちは。
プログラミング初心者Wakinozaと申します。
Java勉強中に調べたことを記事にまとめています。
十分気をつけて執筆していますが、なにぶん初心者が書いた記事なので、理解が浅い点などあるかと思います。
記事を参考にされる方は、初心者の記事であることを念頭において、お読みいただけると幸いです。
間違い等あれば、指摘いただけると助かります。
対象読者
- Javaを勉強中の方
- Java Silver試験を勉強中の方
- Javaの継承の基本事項(オーバーライド以外の項目)についてざっくり知りたい方
目次
1.共通部分をまとめる事の重要性
2.継承とは
3.メンバの継承
4.継承のルール
本文
1. 共通部分をまとめる事の重要性
大規模なプログラムを書いていると、複数のクラスで同じようなコードを書いていたという場面がよく見られます。
しかしこれは、良い状態ではありません。コードが重複していると、1つのコードを変更するために複数箇所を書き直す必要が出てきます。変更の手間が増えますし、変更漏れとなれば予期せぬエラーも引き起こします。
そのため、ソフトウェア開発ではコードが重複しないよう、「共通部分をまとめる事」が重要となります。
Javaで「共通部分をまとめる方法」として、以下の3つが挙げられます。
1,共通する処理をメソッドとして抽出し、分離する
2,共通するコードを別クラスに分離し、分離クラスのインスタンスに処理を受け渡す(委譲)
3,共通するコードを「スーパークラス」として分離し、継承する(継承)
共通する部分がメソッド単位の場合は、1で対応できるでしょう。
共通する部分がクラス単位の場合は、委譲もしくは継承によって共通部分をまとめます。
委譲と継承の使い分けは、ざっくり以下のようになります。
「委譲」: 単純に共通部分をまとめただけの場合や、「has-aの関係」である場合
「継承」: 分離したクラスを階層構造で管理したい場合や、「is-aの関係」である場合
この記事では、継承について説明します。
2. 継承とは
「継承」とは、あるクラスの特性を受け継ぐ、別のクラスを作成する仕組みです。
まず、共通部分を「スーパークラス」として分離します。その上で、スーパークラスを継承する「サブクラス」を定義します。スーパークラスを継承すると、スーパークラスのメンバが自動でサブクラスに引き継がれます。サブクラスは、スーパークラスとの共通部分の記述を省略し、変更点や追加点を記述するだけで定義できます。その上スーパークラスは、複数のサブクラスに継承することができます。
複数のクラスの共通する部分をスーパークラスにまとめることで、コードの重複を避けることができるのです。
継承を定義したい場合は、サブクラスの宣言時に「extends スーパークラス名」を記述します。
具体的な定義方法は、以下のコードをご覧ください。
public class サブクラス名 extends スーパークラス名{
//スーパークラスとの差分
}
また、クラス間の継承関係を図で表す際には、サブクラスからスーパークラスに向かって「白抜き三角と実線」で矢印を書きます。矢印の方向は、サブクラスがスーパークラスの定義に依存しているといった「依存」の関係性を表します。
継承の方向とは逆であるため、少し混乱しやすいポイントです。
「依存」の関係がピンとこない方は、矢印の方向を「相手を知っているか」と考えると、よりイメージしやすいかもしれません。サブクラスはスーパークラスの内容を知っていますが、スーパークラスはサブクラスとの差分を知りません。
なお、継承元のクラスと継承先のクラスの呼び方は、文献や情報によって呼び方が様々です。
この記事では、継承元のクラスを「スーパークラス」、継承先のクラスを「サブクラス」として説明していきます。
もし、ご自分が使っている用語と違って違和感がある場合は、以下の一覧を参考に、適時脳内で言い換えてお読みください。
| 継承元のクラス | 継承先のクラス |
|---|---|
| スーパークラス | サブクラス |
| 親クラス | 子クラス |
| 基底クラス/基本クラス | 派生クラス |
| 導出クラス |
3. メンバの継承
次に、スーパークラスのメンバがどのように継承されているかを見ていきましょう。
継承が定義されても、スーパークラスのメンバ全てがそのまま継承されるわけではありません。
サブクラスに継承されるかどうかは、メンバの種類とそれぞれのアクセス修飾子によって変わります。
1. フィールドとメソッドの継承
まず、フィールドとメソッドです。
フィールドとメソッドが継承されるかどうかは、スーパークラスのアクセス修飾子によって異なります。
アクセス修飾子は、以下のとおりです。
| 名称 | 指定方法 | アクセスを許可する範囲 |
|---|---|---|
| private | private | 自分のクラスのみ |
| package private | 何も書かない | 同じパッケージのクラスのみ |
| protected | protected | 同じパッケージのクラスか自分を継承した子クラスのみ |
| public | public | すべてのクラス |
まず、「private」のフィールド・メソッドは、サブクラスに継承されません。
次に、アクセス修飾子がない「package private」の場合は、サブクラスとスーパークラスが同じパッケージの場合のみ、継承されます。異なるパッケージだった場合は、継承されません。
「protected」と「public」の場合は、パッケージが異なっていても継承されます。
このように、フィールドとメソッドは、スーパークラスでのアクセス修飾子の種類によって、継承されるかどうかが決まるのです。
2. コンストラクタの継承
次に、コンストラクタです。
コンストラクタは、どのようなアクセス修飾子でも、サブクラスに継承されません。
そのため、サブクラスに必要な初期化処理は、サブクラスのコンストラクタで全て定義する必要があります。
ちなみに、継承したフィールドを初期化する場合は、superを使います。
superは、別記事で取り上げるので、この記事では説明を省略します。
4. 継承のルール
継承には、主に3つのルールがあります。
1. 多重継承の禁止
Javaでは、1つのクラスが複数のスーパークラスを継承することができません。これを、「多重継承の禁止」と言います。
もし、多重継承が可能となったら、一体どのようなことが起こるのでしょう。
まず、複数のクラスからそれぞれ同名のメソッドを継承していた場合に、JVMがどのメソッドを利用すれば良いのか判断できない問題(ダイアモンド問題)が発生します。
また、複数のクラスを継承すると、クラス間の関係が複雑になり、コードがわかりにくくなるという問題が発生します。具体的には、サブクラスの処理がどのスーパークラスから継承されたものによるのか、コードを変更した際に影響範囲がどこまでに及ぶのかなどを把握するのが困難になります。
Javaは、多重継承を禁止する事で、ダイアモンド問題を回避し、コードの複雑化を回避し、保守性を高めているのです。
2. 継承の連鎖
Javaの継承は連鎖します。
例えば、クラスAがクラスBを継承し、クラスBがクラスCを継承したとします。この場合、クラスAは、クラスB以外にクラスCも継承しています。。
クラスの階層には特に制限はありませんが、あまり深い階層を作ると、コードが複雑になり保守性が低下します。
継承は5階層を超えないように設計することが、目安となっています。
3. 暗黙の継承
Javaは仕様上、スーパークラスの継承なしではクラスを定義できません。そのため、継承を定義していないクラスには、自動で「java.lang.Objectクラス(以下、Objectクラス)」を継承する仕様になっています。継承を定義しないクラスにObjectクラスを自動的に継承させるこの仕組みを、「暗黙の継承」と言います。
Objectクラスは、Javaのクラスの階層構造の最上位に位置するクラスです。継承の祖先をたどっていくと、全てのクラスはいずれObjectクラスに行き当たります。すなわち、Javaの全てのクラスは暗黙のうちにObjectクラスを継承しているのです。
全てのクラスがObjectクラスを継承していることには、主に2つのメリットがあります。
1,多態性を利用できるようになる
「多態性」を利用すれば、サブクラスのインスタンスをスーパークラスの変数に代入することができます。しかし、多態性の利用は、継承関係があるものに限られます。そのため、多態性を利用する場合は、それらに継承関係があるかどうかを確認する必要がありました。
しかし、Objectクラスは、暗黙の継承によって全てのクラスに継承されています。「全てのクラス is-a Object」であるため、Object型の変数は、全てのクラスのインスタンスを代入できます。(プリミティブ型のデータは代入できません)
具体的には、Objectクラスの変数を利用することで、継承関係を確認することなく多態性を利用したり、全てのクラスのインスタンスを受け取れる汎用性の高い処理を行えたりできるのです。
2,全てのクラスに最低限備えてほしい機能を実装できる
Java言語には、toString()やequals()など全てのクラスが最低限備えておいた方が良い機能が存在します。全てのクラスに継承されるObjectクラスにそれらを記述することで、最低限の機能を保証しています。
まとめ
- ソフトウェアの保守性を高めるために、コードの重複を防ぐことが重要である
- 継承は、コードの共通部分をまとめる手法の一つである。スーパークラスを継承することで、サブクラスはスーパークラスとの共通部分を記述を省略できる
- フィールドをメソッドはアクセス修飾子によって、継承されるかどうかが決まる。コンストラクタは継承されない
- 継承には「多重継承の禁止」「継承の連鎖」「暗黙の継承」というルールがある
記事は以上です。
次回は、オーバーライド・this・super・finalについての記事を書く予定です。
最後までお読みいただき、ありがとうございました。
参考情報一覧
この記事は以下の情報を参考にして執筆しました。
- [オラクル認定資格教科書 JavaプログラマSilverSE11]
- [スッキリわかるJava入門 第4版]
- [パーフェクトJava 改訂3版]
- [なぜ、あなたは、Javaでオブジェクト指向開発ができないのか]
- [11.1 継承と多態性(オーバーライド、抽象クラス、キャスト、ポリモーフィズムなど)~Java Basic編](最終更新 2023-11-05)(https://qiita.com/KenyaSaitoh/items/8fe2ebb65df4753bd907) (参照 2025-05-19)
- [13.1 Objectクラスとオブジェクトの様々な特性(toString()、equals()、hashCode()、同一性と等価性、イミュータブルオブジェクトなど)~Java Basic編](最終更新 2023-11-05)(https://qiita.com/KenyaSaitoh/items/f8ed90168d5fe0e10e62) (参照 2025-05-19)
Discussion