Javaにおけるコンストラクタの手引き
1.はじめに
コンストラクタはhttps://www.baeldung.com/java-polymorphism[
object-oriented design
]のゲートキーパーです。
このチュートリアルでは、作成されるオブジェクトのhttps://www.baeldung.com/java-inheritance-composition[内部状態]を初期化するための単一の場所としてそれらがどのように機能するのかを説明します。
先に進めて、銀行口座を表す単純なオブジェクトを作成しましょう。
2.銀行口座を設定する
銀行口座を表すクラスを作成する必要があるとします。
名前、作成日、残高が表示されます。
また、
toString
メソッドをオーバーライドして詳細をコンソールに表示しましょう。
class BankAccount {
String name;
LocalDateTime opened;
double balance;
@Override
public String toString() {
return String.format("%s, %s, %f",
this.name, this.opened.toString(), this.balance);
}
}
現在、このクラスには銀行口座に関する情報を格納するために必要なすべてのフィールドが含まれていますが、まだコンストラクタは含まれていません。
-
つまり、新しいオブジェクトを作成した場合、フィールド値は初期化されません。**
BankAccount account = new BankAccount();
account.toString();
オブジェクト
name
と
opened
はまだ
null
なので、上記の
__toString
__メソッドを実行すると例外が発生します。
java.lang.NullPointerException
at com.baeldung.constructors.BankAccount.toString(BankAccount.java:12)
at com.baeldung.constructors.ConstructorUnitTest
.givenNoExplicitContructor__whenUsed__thenFails(ConstructorUnitTest.java:23)
3.引数のないコンストラクタ
それをコンストラクタで修正しましょう。
class BankAccount {
public BankAccount() {
this.name = "";
this.opened = LocalDateTime.now();
this.balance = 0.0d;
}
}
先ほど書いたコンストラクタについて、いくつかのことに注意してください。まず、これはメソッドですが、戻り値の型はありません。それは、コンストラクタがそれが作成したオブジェクトの型を暗黙的に返すからです。 new BankAccount()を呼び出すと、上記のコンストラクタが呼び出されます。
第二に、それは引数を取りません。この特定の種類のコンストラクタは、引数なしコンストラクタと呼ばれます。
しかし、なぜ初めて必要にならなかったのでしょうか。これは、コンストラクタを明示的に記述していないときは、デフォルトの引数なしのコンストラクタを追加するためです。
明示的にコンストラクタを記述しなかったにもかかわらず、オブジェクトを初めて構築できたのはこのためです。デフォルトの引数なしのコンストラクタは、すべてのメンバーを単にhttps://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html[デフォルト値]に設定します。
オブジェクトに関しては、それは
null、
です。
4.パラメータ化されたコンストラクタ
現在、コンストラクタの本当の利点は、オブジェクトに状態を注入するときにそれらが
カプセル化
を維持するのを助けるということです。
したがって、この銀行口座で本当に便利なことをするには、オブジェクトに初期値を実際に挿入できる必要があります。
それを行うために、
パラメータ化されたコンストラクタ__、つまりいくつかの引数を取るコンストラクタ
を書きましょう。
class BankAccount {
public BankAccount() { ... }
public BankAccount(String name, LocalDateTime opened, double balance) {
this.name = name;
this.opened = opened;
this.balance = balance;
}
}
これで、
BankAccount
クラスを使用して何か便利なことができます。
LocalDateTime opened = LocalDateTime.of(2018, Month.JUNE, 29, 06, 30, 00);
BankAccount account = new BankAccount("Tom", opened, 1000.0f);
account.toString();
クラスには2つのコンストラクタがあります。明示的な引数なしのコンストラクタおよびパラメータ化されたコンストラクタ
私たちは好きなだけ多くのコンストラクタを作成することができますが、あまり多く作成したくないと思います。これは少しややこしいでしょう。
コード内にコンストラクタが多すぎる場合は、https://www.baeldung.com/creational-design-patterns[Creational Design Patterns]を参考にしてください。
5.コピーコンストラクタ
コンストラクタは初期化だけに限定される必要はありません。彼らはまた行動を作成するために使用することができます。既存のアカウントから新しいアカウントを作成できるようにする必要があると想像してください。
新しいアカウントは、古いアカウントと同じ名前で、今日の作成日で、資金はありません。 **
copyコンストラクター
:を使ってそれを行うことができます。
public BankAccount(BankAccount other) {
this.name = other.name;
this.opened = LocalDateTime.now();
this.balance = 0.0f;
}
今、私たちは以下のように振舞います:
LocalDateTime opened = LocalDateTime.of(2018, Month.JUNE, 29, 06, 30, 00);
BankAccount account = new BankAccount("Tim", opened, 1000.0f);
BankAccount newAccount = new BankAccount(account);
assertThat(account.getName()).isEqualTo(newAccount.getName());
assertThat(account.getOpened()).isNotEqualTo(newAccount.getOpened());
assertThat(newAccount.getBalance()).isEqualTo(0.0f);
6.値の種類
Javaにおけるコンストラクタの興味深い用途は、
Value Objects
の作成です。値オブジェクトは、初期化後に内部状態を変更しないオブジェクトです。
つまり、オブジェクトは不変です。 Javaでの不変性は少しhttps://www.baeldung.com/java-immutable-object[nuanced]であり、オブジェクトを作成するときは注意が必要です。
先に進んで、不変クラスを作成しましょう。
class Transaction {
final BankAccount bankAccount;
final LocalDateTime date;
final double amount;
public Transaction(BankAccount account, LocalDateTime date, double amount) {
this.bankAccount = account;
this.date = date;
this.amount = amount;
}
}
クラスのメンバを定義するときに
final
キーワードを使用するようになりました。つまり、これらの各メンバはクラスのコンストラクタ内でのみ初期化できます。それらは他の方法の中で後で再割り当てすることはできません。これらの値を読むことはできますが、変更することはできません。
-
Transaction
クラスに対して複数のコンストラクタを作成する場合、各コンストラクタはすべての最終変数を初期化する必要があります。
7.まとめ
コンストラクタがオブジェクトを構築するさまざまな方法を見てきました。慎重に使用すると、コンストラクトはJavaのオブジェクト指向設計の基本的な構成要素を形成します。
いつものように、コードサンプルは見つけることができます
https://github.com/eugenp/tutorials/tree/master/core-java-lang-oop
[over
GitHubで。