みんな、Javaの学習は順調かな?以前、継承について学んだよね!クラスが別のクラスの性質を受け継ぐ、あの便利な仕組みのこと。まだ継承について自信がない人は、先に以前の記事で復習しておくのがおすすめだよ。継承の基本:クラスの再利用 | ToolDocs
さて、今回はその継承と密接に関わるsuperキーワードについて深掘りしていくよ。このsuper、まるで親クラスに「ちょっと、そこの君!」って声をかけるような、そんな役割を持っているんだ。
superって何者?
簡単に言うと、superキーワードは**「親クラスのメンバー(フィールドやメソッド)にアクセスするため」**に使うんだ。
「え、でも継承してるんだから、普通に子クラスから親クラスのメンバーを使えるんじゃないの?」って思った人もいるかもしれないね。確かに、多くの場合その通り!親クラスで定義されたpublicやprotectedなフィールドやメソッドは、子クラスから普通に使えるよね。
じゃあ、どんな時にsuperが必要になるのか?主に次の2つのケースで大活躍するんだ。
- 子クラスと親クラスで同じ名前のメンバーがある時
- 親クラスのコンストラクタを呼び出す時
順に見ていこう!
ケース1: 同じ名前のメンバーがある時 (super.フィールド名 / super.メソッド名())
例えば、親クラスと子クラスが同じ名前のフィールドを持っている場合を考えてみよう。
Java
class Animal {
String name = "動物"; // 親クラスのname
void makeSound() {
System.out.println("鳴き声");
}
}
class Dog extends Animal {
String name = "ポチ"; // 子クラスのname
void makeSound() {
// superキーワードを使わずに呼び出すと?
System.out.println(name + "はワンワン!"); // これは子クラスのnameを使う
super.makeSound(); // superを使って親クラスのmakeSoundを呼び出す
}
}
public class SuperKeywordDemo {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.makeSound();
// 実行結果:
// ポチはワンワン!
// 鳴き声
}
}
この例だと、AnimalクラスとDogクラスの両方にnameというフィールドがあるよね。DogクラスのmakeSound()メソッド内でnameと書くと、優先されるのは子クラス(Dogクラス)のnameフィールドなんだ。これは、Javaがまず自分のクラス内で定義されているメンバーを探し、見つかればそれを使うというルールがあるからなんだ。
じゃあ、もしDogクラスの中から親クラスのnameを使いたい場合はどうすればいいか?そこで登場するのがsuper.だよ!
super.nameと書けば、親クラスのAnimalが持っているnameフィールドにアクセスできるんだ。
同じことがメソッドにも言えるよ。DogクラスのmakeSound()メソッド内でsuper.makeSound()と書くと、親クラス(Animalクラス)のmakeSound()メソッドを呼び出すことができるんだ。これはメソッドのオーバーライドと関連が深い話だね。子クラスで親クラスと同じ名前・引数のメソッドを定義すると、子クラスのメソッドが優先的に呼ばれるようになるんだけど、superを使えば、それでも親クラスのメソッドを呼び出せるんだ。

paizaで実行した結果
ケース2: 親クラスのコンストラクタを呼び出す時 (super())
次に、もっと重要な使い方!それが親クラスのコンストラクタを呼び出す場合だよ。
みんな、コンストラクタって覚えているかな?オブジェクトを生成する時に自動的に実行される特別なメソッドのことだよね。
子クラスのオブジェクトを生成する時、実は必ず親クラスのコンストラクタが先に呼ばれるというルールがあるんだ。これは、子クラスが親クラスの性質を受け継ぐために、まず親クラスの準備が整っていなければならないからだよ。
もし、親クラスに引数なしのコンストラクタ(デフォルトコンストラクタ)があれば、Javaが自動的にsuper()を呼び出してくれるから、特に意識する必要はないんだ。
Java
class Vehicle {
Vehicle() { // 引数なしのコンストラクタ
System.out.println("Vehicleのコンストラクタが呼ばれました。");
}
}
class Car extends Vehicle {
Car() { // 子クラスのコンストラクタ
// ここにsuper()が自動的に挿入される(見えないけどね!)
System.out.println("Carのコンストラクタが呼ばれました。");
}
}
public class SuperConstructorDemo {
public static void main(String[] args) {
Car myCar = new Car();
// 実行結果:
// Vehicleのコンストラクタが呼ばれました。
// Carのコンストラクタが呼ばれました。
}
}

paizaで実行した結果
でも、もし親クラスに引数のあるコンストラクタしかない場合はどうだろう?
Java
class Person {
String name;
Person(String name) { // 引数のあるコンストラクタ
this.name = name;
System.out.println("Personのコンストラクタが呼ばれました。名前: " + name);
}
}
class Student extends Person {
int studentId;
Student(String name, int studentId) {
// ここでsuper(name)を呼び出さないとエラーになる!
// なぜなら、Personクラスには引数なしのコンストラクタがないから
super(name); // 親クラスの引数ありコンストラクタを呼び出す
this.studentId = studentId;
System.out.println("Studentのコンストラクタが呼ばれました。学籍番号: " + studentId);
}
}
public class SuperConstructorWithArgsDemo {
public static void main(String[] args) {
Student john = new Student("ジョン", 12345);
// 実行結果:
// Personのコンストラクタが呼ばれました。名前: ジョン
// Studentのコンストラクタが呼ばれました。学籍番号: 12345
}
}
この場合、Studentクラスのコンストラクタの一番最初の行でsuper(name);のように、引数を使って親クラスのコンストラクタを明示的に呼び出す必要があるんだ。これを忘れると、「親クラスのコンストラクタが見つからないよ!」というコンパイルエラーになっちゃうから注意してね!
ポイントは、super()やsuper(引数)は子クラスのコンストラクタの一番最初の文として書かなければならないってこと。他の処理を書いた後にsuper()を書くとエラーになるよ。

paizaで実行した結果
thisとsuper、似てるけど違う!
ここで、前回の記事で触れたかもしれないthisキーワードと比較してみよう。
this: 自分自身のクラスのメンバー(フィールドやメソッド)やコンストラクタにアクセスする時に使う。super: 親クラスのメンバー(フィールドやメソッド)やコンストラクタにアクセスする時に使う。
似ているようで役割が全然違うのがわかるよね!
まとめ
今回はsuperキーワードについて学んだね。
super.フィールド名:親クラスのフィールドにアクセスsuper.メソッド名():親クラスのメソッドにアクセスsuper()またはsuper(引数):親クラスのコンストラクタを呼び出す
特に、子クラスで親クラスと同じ名前のメンバーを扱ったり、親クラスに引数ありのコンストラクタしかない場合は、superキーワードが必須になるんだ。
継承を使いこなす上で、superキーワードは欠かせない存在!しっかりとマスターして、Javaのプログラミングをもっと楽しく、効率的に進めていこうね!
もし分からないことがあれば、いつでも質問してね!次の記事もお楽しみに!


コメント