Java
2022.02.23
Javaのsuperとは?使い方をマスターして初心者を脱出しよう
2023.11.18

Javaのプログラミング学習をするうえで、「superの使い方がわからない」と悩んでいる方も多いのではないでしょうか。


「親クラスのメソッドの呼び出しはどうやって書くのだろうか?」

「superとthisの違いは?」


といった疑問に対して、本記事ではJavaのsuperの使い方をサンプルを交えて解説していきます。


※本記事で紹介するサンプルコードは、macOS Montere、OpenJDK-11.0.13で動作確認しています。


1.Javaのsuperとは?

superは、Javaのサブクラスでオーバーライドされた変数やインスタンスを参照する場合に使用します。子インスタンスから親クラスのメンバにアクセスして、値を参照できます。



2.継承とコンストラクタについておさらい


superについて詳しく説明する前に、Javaの継承とコンストラクタについておさらいしておきましょう。

①継承とは

Javaクラスの継承は、既存の機能と共通する部分を引き継ぎ、新しい機能を作るときに使用します。Javaなどのオブジェクト指向プログラミングの基本的な概念です。


以下にクラスの継承を使用したサンプルを紹介します。

public class App {
    public static void main(String[] args) {
        DogClass dog = new DogClass();
        dog.setName("タロウ");
        dog.bark();
    }
}

//親クラス
class AnimalClass{
    private String name;
    AnimalClass(){
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}

//子クラス
class DogClass extends AnimalClass{
    DogClass(){
    }
    public void bark(){
        System.out.println(this.getName() + "が、わんわんと吠えた。");
    }
}

実行結果:

タロウが、わんわんと吠えた。

サンプルでは、親クラスのAnimalClassと親クラスを継承した子クラスのDogClassがあります。


mainメソッドからDogClassのインスタンスを作成すると、継承元のAnimalClassが参照されます。継承の機能により、DogClassクラスから親クラスのsetName()メソッドやgetName()メソッドが使用できることがわかりますね。

②コンストラクタとは

コンストラクタとは、クラスをインスタンス化する際に実行されるメソッドで、主にクラスのメンバ変数を初期化するときに使われます。


コンストラクタの書き方は、以下のルールを守る必要があります。


・コンストラクタはメソッド名とクラス名を同一にする

・戻り値を記述しない

以下は、コンストラクタの書き方のサンプルです。

public class App {
    public static void main(String[] args) {
        ConstructorSample cs = new ConstructorSample();
    }
}

//コンストラクタ
class ConstructorSample{
    public ConstructorSample(){
        System.out.println("コンストラクタのサンプル");
    }
}

実行結果:

コンストラクタのサンプル

ConstructorSampleクラスをインスタンス化する際に、コンストラクタが呼び出されます。



3.superの基本的な使い方


superの基本的な使い方について、サンプルコードと共に解説していきます。

①親クラスのコンストラクタを呼び出す

子クラスからsuperを使って親クラスのコンストラクタを呼び出すサンプルを紹介します。

public class App {
    public static void main(String[] args) {
        ChildClass child = new ChildClass();
    }
}

class ParentClass{
    public ParentClass(){
        System.out.println("Parent_Constructor");
    }
    public ParentClass(String str){
        System.out.println("My name is " + str);
    }
}

class ChildClass extends ParentClass{
    public ChildClass(){
        //親クラスのString型引数のコンストラクタを呼び出す
        super("Taro");
    }
}

実行結果:

My name is Taro

コンストラクタが呼び出される順番

サンプルプログラムは、mainメソッドでChildClassをインスタンス化する際に、ChildClassのコンストラクタを呼び出します。


ChildClassのコンストラクタ内で、superの引数に”Taro”を指定しているので、親クラスの該当するString型の引数があるコンストラクタが呼び出されています。

②親クラスのメソッドを呼び出す

superを使用し親クラスのメソッドを呼び出すサンプルコードを見てみましょう。

public class App {
    public static void main(String[] args) {
        ChildClass child = new ChildClass();
        child.printName();
    }
}

class ParentClass{
    String lastname = "Suzuki";
    public void dispName(){
        System.out.println("My last name is " + lastname);
    }
}

class ChildClass extends ParentClass{
    public void printName(){
        super.dispName();
    }
}

実行結果:

My last name is Suzuki

このように、superを使って親クラスのメソッドを呼び出せます。

③親クラスのフィールドを参照する

superを使用し、親クラスのフィールドを参照するサンプルコードを紹介します。

public class App {
    public static void main(String[] args) {
        ChildClass child = new ChildClass();
        child.printParentsAge();
    }
}

class ParentClass{
    String name = "Ichiro";
    int age = 33;
    public String getName(){
        return name;
    }
}

class ChildClass extends ParentClass{
    int age = 8;
    public void printParentsAge(){
        System.out.println("I'm " + age + " years old");
        System.out.println("My parent is " + super.age + " years old");
    }
}

実行結果:

I'm 8 years old
My parent is 33 years old

superを使うと親クラスの隠蔽されたフィールドを参照でき、superを使わない場合は自身のフィールドが参照されることが確認できます。



4.superを使う際の注意点

ここで、superを使う際の注意点を3つ紹介します。

①2つ上の親クラスは呼び出せない

superは2つ上の親クラスのフィールドやコンストラクタを参照できません。

public class App {
    public static void main(String[] args) {
        GrandchildClass mago = new GrandchildClass();
        mago.familyIntroduction();
    }
}

class ParentClass{
    int age = 62;
    public int getAge(){
        return age;
    }
}

class ChildClass extends ParentClass{
    int age = 33;
    public void  familyIntroduction(){
        System.out.println("My parents is " + super.age + " years old");
    }
}

class GrandchildClass extends ChildClass{
    int age =8;
    public void familyIntroduction(){
        System.out.println("I'm " + age + " years old");
        System.out.println("My father is " + super.age + " years old");
        //2つ上の親クラスはsuperを使っても呼び出せない
        System.out.println("My grandfather is " + super.age + " years old");
    }
}

実行結果:

I'm 8 years old
My father is 33 years old
My grandfather is 33 years old

grandfatherを62歳と紹介したいのに、「My grandfather is 33 years old」となってしまいますね。


別手段で2つ上の親クラスのフィールドを参照することはできますが、オブジェクト指向の手法から逸脱するので、クラス設計から見直すことをおすすめします。

②superを使わないと暗黙的にsuper()を呼ぶ

子クラスでsuperを使わないと、暗黙的に親クラスの引数なしのコンストラクタを呼びます。

public class App {
    public static void main(String[] args) {
        ChildClass child = new ChildClass();
    }
}

 class ParentClass{
    int age = 32;
    public ParentClass(){
        System.out.println("I'm " + age + " years old");
    }
    public ParentClass(String introduction){
        System.out.println("My parents are " + age + " years old");
    }
}

class ChildClass extends ParentClass{
    int age = 8;
    public ChildClass(){
        System.out.println("I'm " + age + " years old");
    }
}

実行結果:

I'm 32 years old
I'm 8 years old

明示的にsuperを使った場合は、「暗黙的に親クラスの引数なしのコンストラクタ呼び出し」はされず、引数の型にあったコンストラクタが呼ばれます。

public class App {
    public static void main(String[] args) {
        ChildClass child = new ChildClass();
    }
}

 class ParentClass{
    int age = 32;
    public ParentClass(){
        System.out.println("I'm " + age + " years old");
    }
    public ParentClass(String introduction){
        System.out.println("My parents are " + age + " years old");
    }
}

class ChildClass extends ParentClass{
    int age = 8;
    public ChildClass(){
        super("Parent introduction");
        System.out.println("I'm " + age + " years old");
    }
}

実行結果:

My parents are 32 years old
I'm 8 years old

もし親クラスで引数ありのコンストラクタしか定義されていなかったら、明示的にsuperを使わないとコンパイルエラーが発生するので注意が必要です。

③staticからsuperへはアクセス不可

staticは特定のインスタンスと紐づかないメソッドなので、インスタンスがない前提で呼ばれます。そのため、staticメソッドから特定のインスタンスに紐づくフィールドやメソッドは参照できません。



5.superとthisの違い


Javaプログラミングには、superとよく似た役割をもつ「this」というキーワードがあります。ここではsuperとthisの違いについて、サンプルコードを用いて解説します。

public class App {
    public static void main(String[] args) {
        ChildClass child = new ChildClass();
        child.familyIntroduction();
    }
}

class ParentClass{
    int age = 53;
    String Name = "Ichiro";
}

class ChildClass extends ParentClass{
    int age = 28;
    String Name = "Taro";
    public void  familyIntroduction(){
        System.out.println("My parents name is " + super.Name);
        System.out.println(super.Name + " is " + super.age + " years old");
        System.out.println("My name is " + this.Name);
        System.out.println("I'm " + this.age + " years old");
    }
}

実行結果:

My parents name is Ichiro
Ichiro is 53 years old
My name is Taro
I'm 28 years old

これまで解説してきた通り、superは親クラスの変数やコンストラクタにアクセスする際に使用します。一方、thisは自分のクラスの変数やメソッドにアクセスするために使用するのです。


この記事をシェア