Menu
Coddy logo textTech

コンストラクタチェーン

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 23/87。

コンストラクタ・チェイニングは、あるコンストラクタから別のコンストラクタを呼び出すプロセスのことです。この手法は、クラスに複数のコンストラクタがある場合や、継承階層を扱う場合にコードの重複を避けるのに役立ちます。

同じクラス内で、this() を使用してコンストラクタを連結させることができます。これにより、すべての処理を行う1つの「メイン」コンストラクタを持ち、他のコンストラクタは単にそれに処理を委譲するようにできます:

public class Rectangle {
    private int width;
    private int height;
    
    public Rectangle() {
        this(1, 1);  // 2つの引数を持つコンストラクタを呼び出します
    }
    
    public Rectangle(int size) {
        this(size, size);  // 正方形を作成します
    }
    
    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

継承において、コンストラクタ・チェイニングは自動的に発生します。サブクラスのオブジェクトを作成すると、Javaはまずsuper()を使用して親のコンストラクタを呼び出します。明示的にsuper()を呼び出さない場合、Javaは自動的にsuper()(引数なしのバージョン)を挿入します:

public class Animal {
    private String name;
    
    public Animal(String name) {
        this.name = name;
        System.out.println("Animal constructor");
    }
}

public class Dog extends Animal {
    private String breed;
    
    public Dog(String name, String breed) {
        super(name);  // 最初の行である必要があります
        this.breed = breed;
        System.out.println("Dog constructor");
    }
}

new Dog("Buddy", "Labrador") を作成すると、最初に "Animal constructor" が出力され、次に "Dog constructor" が出力されます。これにより、子クラスが独自のセットアップを追加する前に、親クラスが常に適切に初期化されることが保証されます。

challenge icon

チャレンジ

簡単

クラス内および継承階層全体でのコンストラクタチェーンを実証する製品注文システムを構築しましょう。this() が同じクラス内のコンストラクタをチェーンし、super() が親のコンストラクタにチェーンする仕組みを確認します。

コードを整理するために3つのファイルを作成します:

  • Product.java: 店舗内の任意の製品を表す親クラスを作成します。以下の内容を含める必要があります:
    • name (String) と price (double) のプライベートフィールド
    • 名前と価格の両方を受け取り、フィールドを初期化して、"Product constructor: " + name を出力するメインコンストラクタ
    • 名前のみを受け取り、this(name, 0.0) を使用してメインコンストラクタにチェーンし、デフォルト価格を 0.0 に設定する2番目のコンストラクタ
    • フィールドにアクセスするための getName() および getPrice() メソッド
  • Electronics.java: Product を継承し、保証情報を追加するサブクラスを作成します:
    • warrantyYears (int) のプライベートフィールド
    • 名前、価格、および warrantyYears を受け取るメインコンストラクタ。super(name, price) を使用して親を初期化し、次に保証期間を設定して、"Electronics constructor: " + warrantyYears + " year warranty" を出力します
    • 名前と価格のみを受け取り、this(name, price, 1) を使用してメインコンストラクタにチェーンし、デフォルトの1年保証を提供する2番目のコンストラクタ
    • 名前のみを受け取り、this(name, 0.0) を使用して2番目のコンストラクタにチェーンする3番目のコンストラクタ
    • getName() + " - $" + String.format("%.2f", getPrice()) + " (" + warrantyYears + " year warranty)" を返す getDetails() メソッド
  • Main.java: コンストラクタチェーンの動作を実証します。製品名 (String)、価格 (double)、保証年数 (int) の3つの入力を受け取ります。これら3つのパラメータすべてを使用して Electronics オブジェクトを作成し、getDetails() の結果を出力してください。

製品名、価格、保証年数の3つの入力を受け取ります。

getDetails() 内の価格は、String.format("%.2f", price) を使用して小数点以下2桁まで表示するようにフォーマットしてください。出力に注目してください。コンストラクタのメッセージが順番に表示され、親から子へとチェーンが流れる様子がわかります!

チートシート

コンストラクタ・チェイニング(Constructor chaining)とは、コードの重複を避けるために、あるコンストラクタから別のコンストラクタを呼び出すプロセスのことです。

同じクラス内でのチェイニング

同じクラス内の別のコンストラクタを呼び出すには、this() を使用します:

public class Rectangle {
    private int width;
    private int height;
    
    public Rectangle() {
        this(1, 1);  // Calls the two-parameter constructor
    }
    
    public Rectangle(int size) {
        this(size, size);  // Creates a square
    }
    
    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

継承におけるチェイニング

親クラスのコンストラクタを呼び出すには、super() を使用します。これはコンストラクタの最初の行になければなりません:

public class Animal {
    private String name;
    
    public Animal(String name) {
        this.name = name;
        System.out.println("Animal constructor");
    }
}

public class Dog extends Animal {
    private String breed;
    
    public Dog(String name, String breed) {
        super(name);  // Must be first line
        this.breed = breed;
        System.out.println("Dog constructor");
    }
}

明示的に super() を呼び出さない場合、Javaは自動的に super()(引数なしのバージョン)を挿入します。親のコンストラクタは常に子のコンストラクタよりも前に呼び出され、適切な初期化順序が保証されます。

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 入力を読み込む
        String name = scanner.nextLine();
        double price = scanner.nextDouble();
        int warrantyYears = scanner.nextInt();
        
        // TODO: 3つすべてのパラメータを使用して Electronics オブジェクトを作成する
        
        // TODO: getDetails() の結果を出力する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン