継承(extends)、多態性(オーバーライド)
まえがき
chat-gptで作った学習ロードマップをプログラミング初学者が勉強する試みです
ロードマップはchat-gptを使用してますが、学習は公式のチュートリアルや技術系ブログなどを参考にしています
Goの復習も兼ねているのでGoとの違いについても言及します
今回は継承(extends)、多態性(オーバーライド)について内容をまとめていきます
継承とは?
概要
クラスAからクラスBへと派生させることで、クラスAのフィールドとメソッドをクラスBへと継承させること
それぞれの関係性はそれぞれからみて
-
クラスA
スーパークラス(基本クラス、親クラスとも呼ぶ) -
クラスB
サブクラス(派生クラス、拡張クラス、子クラスとも呼ぶ)
また全てのクラスはobject
から派生している
目的
同じようなクラスを作成するときにクラスを継承させることで、フィールドやメソッドを書かずに再利用できる
フィールドやメソッドの追加もできるので、サブクラスはスーパークラスを拡張したものといえる
実装方法
// スーパークラス
class A {
}
// サブクラス
class B extends A {
}
クラス名のあとにextends
キーワードと、継承元のスーパークラスをつけると継承できる
実装例
// スーパークラスのメンバーには全てのAnimalが持つべき要素を記述する
class Animal {
int x; // x軸の位置情報
int y; // y軸の位置情報
void getPosition() {
System.out.print(x + ", " + y);
}
}
// サブクラスのメンバーには種類毎に異なる要素を追加できる
// Animalを継承しているのでフィールド`x, y`やメソッド`getPosition`も使える
class Cat extends Animal {
void walk() {
x += 1;
}
}
class Bird extends Animal {
void fly() {
y += 1;
}
}
共通の機能をAnimal
に持たせているので、全てのサブクラスが位置情報フィールドや現在地の出力などを使える
Cat
は横方向に動くのでx軸の変化
Bird
は縦方向に動くのでy軸の変化
多態性(オーバーライド)とは
多態性(ポリモーフィズム)とオーバーライドは別の概念なので見出しを変えようかと思ったが、多態性を実装するにあたってオーバーライドは必須だったので、あえてそのままの見出しで使うことにした
というのも先ほどの継承例で使ったように、メソッドの追加をしただけでは多態性が実現しなかった
オーバーライドとは
概要
継承元(スーパークラス)のインスタンスメソッドと”同じシグネチャ・返り値”を持つサブクラスのインスタンスメソッドは、継承元のインスタンスメソッドをオーバーライドする
端的にいうとスーパークラスのメソッドをサブクラスで上書きする機能のこと
目的
サブクラスごとに独自のメソッドを持たせることができる
実装
class Animal {
void makeSound() {
System.out.print("動物の鳴き声");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.print("meow");
}
}
@Override
アノテーションを付けることが推奨される
アノテーションを付けることで継承元にメソッドが無かったり、シグネチャが違う場合にはコンパイラが教えてくれる
多態性(ポリモーフィズム)とは
概要
多態性=ポリモーフィズムとは共通のインターフェースを通じて、異なるオブジェクトがそれぞれ別の振るまいをする仕組みのこと
目的
コードの柔軟性・再利用性・メンテナンス性が向上する
インスタンスをまとめてスーパークラス型で扱い、それぞれのサブクラスとして振るまわせることができる
実装
継承の「サブクラスはスーパークラスの一種である」という性質を利用する
先ほどの例で言えば「Cat
はAnimal
の一種である」ということ
つまりAnimal型
のオブジェクトにはCat
が代入できる、それはCat
として振るまう
このように上位のクラス型へ変換することをアップキャストという(反対はダウンキャスト)
class Animal {
void makeSound() {
System.out.print("動物の鳴き声");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.print("meow");
}
}
public class Main {
public static void main(String[] args) {
// これは通常のインスタンス初期化
Animal a = new Animal();
a.makeSound(); // 動物の鳴き声
// Animal型のオブジェクトだが実体はCatクラス(暗黙的にアップキャストされる)
Animal neko = new Cat();
neko.makeSound(); // meow
}
}
JavaとGoの違い
Goでは継承やオーバーライドの概念は無いので割愛する
埋め込み(embedded)が継承に近いが、Goの埋め込みはJavaでいうところの委譲にあたる
多態性もインターフェースを使って実装するのでここでは割愛する
まとめ
継承、オーバーライド、多態性について調べた
なるべく単純な機能にフォーカスして書こうと思ったが、それぞれが密接していて切り離すのが意外と難しかった
特にオーバーライドを利用した多態性は、Goとは実装方法が違ったので混乱したが思ったよりもシンプルだった
次回はインターフェース(interface)と抽象クラス(abstract)について調べる
それとロードマップに無かったので委譲についても触れたいと思う
初学者なので間違ってる部分があればご指摘いただけると嬉しいです
Discussion