この章で得られるスキル:
✅ オブジェクト作成時に自動で初期値を設定できる
✅ 不正な値でのオブジェクト作成を防げる
✅ 複数パターンの初期化方法を提供できる
✅ より安全で使いやすいクラスが設計できる
Step 0: コンストラクタがないとどうなる?
まず、コンストラクタを使わずにインスタンスを初期化してみよう。
問題シナリオ:銀行口座の管理
銀行口座を表すBankAccountクラスを作り、口座名義人と残高を管理したいとする。
コンストラクタを使わない場合:
class BankAccount {
String owner;
int balance;
void showInfo() {
System.out.println("口座名義: " + owner + ", 残高: " + balance + "円");
}
}
public class Main {
public static void main(String[] args) {
// インスタンス生成後、手動で初期化
BankAccount account1 = new BankAccount();
account1.owner = "太郎";
account1.balance = 10000;
account1.showInfo();
// 初期化を忘れた場合
BankAccount account2 = new BankAccount();
// account2.ownerとbalanceを設定し忘れた!
account2.showInfo(); // null と 0 が表示される
}
}
実行結果:
口座名義: 太郎, 残高: 10000円 口座名義: null, 残高: 0円
問題点
このコードには、いくつかの深刻な問題がある:
1. 初期化を忘れる可能性
account2のように、フィールドの設定を忘れるとnullや0のままになる
銀行口座で名義人がnullなのは致命的
2. 不完全な状態のインスタンスが存在できる
インスタンス生成と初期化が分離しているため、「生成されたが初期化されていない」状態が存在する
これはバグの温床になる
3. 初期化コードの重複
口座を作るたびに、同じ初期化コードを書く必要がある
コピペが増え、保守性が低下する
4. 必須フィールドの強制ができない
「口座名義人は必須」というルールをコードで強制できない
実行時まで気づかず、バグになる
理想的な形
こうできたら良いのに:
BankAccount account = new BankAccount ( "太郎" , 10000 ) ;
これを実現するのが コンストラクタ である。
Step 1: コンストラクタという解決策
コンストラクタとは
コンストラクタ は、インスタンス生成時に自動的に呼ばれる特別なメソッド である。
主な役割は、インスタンスの 初期化 (フィールドに初期値を設定すること)である。
コンストラクタの特徴
特徴 説明 クラス名と同じ名前 BankAccountクラスなら、コンストラクタ名もBankAccount戻り値がない voidすら書かないnewと一緒に呼ばれるnew BankAccount()で自動的に実行される初期化専用 フィールドに初期値を設定するのが主な役割
コンストラクタのメリット
初期化の強制 :インスタンス生成時に必ず初期化される
不完全な状態の排除 :生成と初期化が同時に行われる
コードの簡潔化 :初期化コードを一箇所にまとめられる
必須フィールドの明示 :引数で「何が必須か」が明確になる
Step 2: コンストラクタの基本的な定義
基本的な書き方
class クラス名 { 型 フィールド名 ; クラス名 ( 引数 ) { } }
例:BankAccountクラス
class BankAccount {
String owner;
int balance;
// コンストラクタ
BankAccount(String owner, int balance) {
this.owner = owner;
this.balance = balance;
System.out.println("口座を作成しました");
}
void showInfo() {
System.out.println("口座名義: " + owner + ", 残高: " + balance + "円");
}
}
public class Main {
public static void main(String[] args) {
// コンストラクタを使ってインスタンスを作成
BankAccount account1 = new BankAccount("太郎", 10000);
account1.showInfo();
BankAccount account2 = new BankAccount("花子", 5000);
account2.showInfo();
// 初期化を忘れることができない!
// BankAccount account3 = new BankAccount(); // エラー!
}
}
コードの解説
BankAccount ( String owner , int balance ) { this . owner = owner ; this . balance = balance ; }
BankAccount :クラス名と同じ名前
引数 :ownerとbalanceを受け取る
this.owner :フィールドのowner
owner :引数のowner
thisキーワードで、フィールドと引数を区別している。
コンストラクタの呼び出し
BankAccount account = new BankAccount ( "太郎" , 10000 ) ;
newキーワードでインスタンスを生成すると、自動的にコンストラクタが呼ばれる。
Step 3: thisキーワードの役割
thisキーワードとは
thisキーワード は、自分自身のインスタンス を指す。
用途1:フィールドと引数を区別
フィールドと引数が同じ名前の場合、thisでフィールドを明示する。
class Person {
String name;
int age;
// 引数とフィールドが同じ名前
Person(String name, int age) {
this.name = name; // this.nameはフィールド、nameは引数
this.age = age; // this.ageはフィールド、ageは引数
}
void introduce() {
System.out.println("私の名前は" + name + "で、" + age + "歳です");
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("太郎", 18);
person.introduce();
}
}
thisがないとどうなるか
class Person {
String name;
int age;
// thisを付けない場合
Person(String name, int age) {
name = name; // 引数のnameに引数のnameを代入(意味がない)
age = age; // 引数のageに引数のageを代入(意味がない)
}
void introduce() {
System.out.println("私の名前は" + name + "で、" + age + "歳です");
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("太郎", 18);
person.introduce(); // null と 0 が表示される
}
}
実行結果:
フィールドが初期化されていない!thisは必須である。
用途2:自分自身を返す(メソッドチェーン)
class Person { String name ; int age ; Person ( String name , int age ) { this . name = name ; this . age = age ; } Person setName ( String name ) { this . name = name ; return this ; } Person setAge ( int age ) { this . age = age ; return this ; } } Person person = new Person ( "太郎" , 18 ) . setName ( "次郎" ) . setAge ( 20 ) ;
これは発展的な内容なので、今は理解しなくても良い。
Step 4: デフォルトコンストラクタ
デフォルトコンストラクタとは
デフォルトコンストラクタ は、引数がないコンストラクタ である。
自動で用意される場合
コンストラクタを1つも定義しなかった場合 、Javaコンパイラが自動的にデフォルトコンストラクタを用意してくれる。
class Person {
String name;
int age;
// コンストラクタを定義していない
}
public class Main {
public static void main(String[] args) {
// 自動的にデフォルトコンストラクタが用意される
Person person = new Person(); // OK
person.name = "太郎";
person.age = 18;
System.out.println(person.name + "は" + person.age + "歳です");
}
}
自動で用意されない場合
引数ありのコンストラクタを定義した場合 、デフォルトコンストラクタは自動で用意されない。
class Person {
String name;
int age;
// 引数ありのコンストラクタを定義
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
// デフォルトコンストラクタは用意されない
// Person person = new Person(); // エラー!
// 引数ありのコンストラクタを使う必要がある
Person person = new Person("太郎", 18);
System.out.println(person.name + "は" + person.age + "歳です");
}
}
明示的にデフォルトコンストラクタを定義
引数ありのコンストラクタを定義しつつ、デフォルトコンストラクタも使いたい場合は、明示的に定義する。
class Person {
String name;
int age;
// デフォルトコンストラクタ(明示的に定義)
Person() {
this.name = "名無し";
this.age = 0;
System.out.println("デフォルトコンストラクタが呼ばれました");
}
// 引数ありのコンストラクタ
Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("引数ありのコンストラクタが呼ばれました");
}
void introduce() {
System.out.println("私の名前は" + name + "で、" + age + "歳です");
}
}
public class Main {
public static void main(String[] args) {
// デフォルトコンストラクタを使用
Person person1 = new Person();
person1.introduce();
System.out.println("---");
// 引数ありのコンストラクタを使用
Person person2 = new Person("太郎", 18);
person2.introduce();
}
}
引数ありのコンストラクタを定義した場合、デフォルトコンストラクタも使いたいなら、明示的に定義する必要がある。
Step 5: コンストラクタのオーバーロード
オーバーロードとは
メソッドと同様に、コンストラクタもオーバーロードできる 。
異なる引数のコンストラクタを複数定義できる。
例:複数のコンストラクタ
class Car {
String color;
String maker;
int speed;
// コンストラクタ1:引数なし
Car() {
this.color = "白";
this.maker = "トヨタ";
this.speed = 0;
System.out.println("デフォルトの車を作成しました");
}
// コンストラクタ2:色のみ指定
Car(String color) {
this.color = color;
this.maker = "トヨタ";
this.speed = 0;
System.out.println(color + "の車を作成しました");
}
// コンストラクタ3:色とメーカーを指定
Car(String color, String maker) {
this.color = color;
this.maker = maker;
this.speed = 0;
System.out.println(color + "の" + maker + "車を作成しました");
}
// コンストラクタ4:全てのフィールドを指定
Car(String color, String maker, int speed) {
this.color = color;
this.maker = maker;
this.speed = speed;
System.out.println(color + "の" + maker + "車(速度" + speed + ")を作成しました");
}
void showInfo() {
System.out.println("色: " + color + ", メーカー: " + maker + ", 速度: " + speed);
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car();
car1.showInfo();
System.out.println("---");
Car car2 = new Car("赤");
car2.showInfo();
System.out.println("---");
Car car3 = new Car("青", "ホンダ");
car3.showInfo();
System.out.println("---");
Car car4 = new Car("黒", "日産", 80);
car4.showInfo();
}
}
使い分け
コンストラクタ1 :何も指定しない(デフォルト値)
コンストラクタ2 :色だけ変えたい
コンストラクタ3 :色とメーカーを変えたい
コンストラクタ4 :全て指定したい
状況に応じて、適切なコンストラクタを選べる。
Step 6: this()でコンストラクタを連鎖させる
コンストラクタの重複を減らす
複数のコンストラクタを定義すると、初期化コードが重複することがある。
重複がある例:
class Car { String color ; String maker ; int speed ; Car ( ) { this . color = "白" ; this . maker = "トヨタ" ; this . speed = 0 ; } Car ( String color ) { this . color = color ; this . maker = "トヨタ" ; this . speed = 0 ; } Car ( String color , String maker ) { this . color = color ; this . maker = maker ; this . speed = 0 ; } }
this()で別のコンストラクタを呼ぶ
this()を使うことで、コンストラクタから別のコンストラクタを呼べる。
class Car {
String color;
String maker;
int speed;
// コンストラクタ1:引数なし
Car() {
this("白", "トヨタ", 0); // コンストラクタ4を呼ぶ
}
// コンストラクタ2:色のみ指定
Car(String color) {
this(color, "トヨタ", 0); // コンストラクタ4を呼ぶ
}
// コンストラクタ3:色とメーカーを指定
Car(String color, String maker) {
this(color, maker, 0); // コンストラクタ4を呼ぶ
}
// コンストラクタ4:全てのフィールドを指定(メインコンストラクタ)
Car(String color, String maker, int speed) {
this.color = color;
this.maker = maker;
this.speed = speed;
System.out.println(color + "の" + maker + "車(速度" + speed + ")を作成しました");
}
void showInfo() {
System.out.println("色: " + color + ", メーカー: " + maker + ", 速度: " + speed);
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car();
car1.showInfo();
System.out.println("---");
Car car2 = new Car("赤");
car2.showInfo();
System.out.println("---");
Car car3 = new Car("青", "ホンダ");
car3.showInfo();
System.out.println("---");
Car car4 = new Car("黒", "日産", 80);
car4.showInfo();
}
}
メリット
初期化ロジックが一箇所に集約 :コンストラクタ4だけがフィールドを設定
保守性の向上 :初期化ロジックを変更する際、1箇所だけ修正すればよい
バグの削減 :重複コードがないため、バグが入りにくい
this()でコンストラクタを呼ぶ場合、コンストラクタの最初の行 に書く必要がある。
エラーになる例:
Car ( ) { System . out . println ( "デフォルト車を作成" ) ; this ( "白" , "トヨタ" , 0 ) ; }
Step 7: コンストラクタの実践パターン
パターン1:必須フィールドの強制
必須フィールドは引数ありコンストラクタで強制し、デフォルトコンストラクタは提供しない。
class User {
String username; // 必須
String email; // 必須
int age; // オプション
// 必須フィールドを引数で受け取る
User(String username, String email) {
this.username = username;
this.email = email;
this.age = 0; // デフォルト値
}
// デフォルトコンストラクタは提供しない
// User() { } // これを定義しないことで、必須フィールドの設定を強制
void showInfo() {
System.out.println("ユーザー名: " + username + ", メール: " + email + ", 年齢: " + age);
}
void setAge(int age) {
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
// 必須フィールドを指定しないとインスタンスを作れない
// User user1 = new User(); // エラー!
// 必須フィールドを指定
User user1 = new User("taro", "taro@example.com");
user1.showInfo();
// オプションフィールドはsetterで設定
user1.setAge(25);
user1.showInfo();
}
}
パターン2:バリデーション(検証)
コンストラクタ内で引数の妥当性をチェックする。
class BankAccount {
String owner;
int balance;
BankAccount(String owner, int balance) {
// バリデーション:名義人が空でないか
if (owner == null || owner.isEmpty()) {
System.out.println("エラー: 名義人を指定してください");
this.owner = "名無し";
} else {
this.owner = owner;
}
// バリデーション:残高が負でないか
if (balance < 0) {
System.out.println("エラー: 残高は0以上で指定してください");
this.balance = 0;
} else {
this.balance = balance;
}
System.out.println("口座を作成しました");
}
void showInfo() {
System.out.println("口座名義: " + owner + ", 残高: " + balance + "円");
}
}
public class Main {
public static void main(String[] args) {
// 正常なケース
BankAccount account1 = new BankAccount("太郎", 10000);
account1.showInfo();
System.out.println("---");
// 名義人が空のケース
BankAccount account2 = new BankAccount("", 5000);
account2.showInfo();
System.out.println("---");
// 残高が負のケース
BankAccount account3 = new BankAccount("花子", -1000);
account3.showInfo();
}
}
パターン3:イミュータブル(不変)オブジェクト
コンストラクタで全フィールドを設定し、setterを提供しないことで、不変オブジェクトを作る。
class Point { final int x ; final int y ; Point ( int x , int y ) { this . x = x ; this . y = y ; } } Point p = new Point ( 10 , 20 ) ;
不変オブジェクトは、スレッドセーフで安全である。
Step 8: 実践課題
ここまで学んだ知識を使って、以下の3つの課題に挑戦しよう。
課題1: Bookクラスの作成
要件 :
Bookクラスを定義する
フィールド:title(String)、author(String)、price(int)、pages(int)
コンストラクタ1:全てのフィールドを引数で受け取る
コンストラクタ2:titleとauthorのみ受け取る(priceとpagesはデフォルト値0)
メソッド:showInfo()で全情報を表示
2冊の本を作成し、それぞれ異なるコンストラクタを使う
ヒント :
Book book1 = new Book ( "Javaの教科書" , "山田太郎" , 3000 , 500 ) ; Book book2 = new Book ( "データベース入門" , "田中花子" ) ;
解答例を見る class Book {
String title;
String author;
int price;
int pages;
// コンストラクタ1:全てのフィールドを指定
Book(String title, String author, int price, int pages) {
this.title = title;
this.author = author;
this.price = price;
this.pages = pages;
}
// コンストラクタ2:titleとauthorのみ指定
Book(String title, String author) {
this(title, author, 0, 0); // コンストラクタ1を呼ぶ
}
void showInfo() {
System.out.println("『" + title + "』 著者: " + author + ", 価格: " + price + "円, ページ数: " + pages);
}
}
public class Main {
public static void main(String[] args) {
Book book1 = new Book("Javaの教科書", "山田太郎", 3000, 500);
book1.showInfo();
Book book2 = new Book("データベース入門", "田中花子");
book2.showInfo();
}
}
課題2: Rectangleクラスの作成
要件 :
Rectangle(長方形)クラスを定義する
フィールド:width(int)、height(int)
コンストラクタ1:引数なし(デフォルト値:width=10, height=10)
コンストラクタ2:一辺のみ指定(正方形)
コンストラクタ3:widthとheightを指定
メソッド:getArea()で面積を返す、showInfo()で情報を表示
3つの長方形を作成し、それぞれ異なるコンストラクタを使う
ヒント :
Rectangle rect1 = new Rectangle ( ) ; Rectangle rect2 = new Rectangle ( 5 ) ; Rectangle rect3 = new Rectangle ( 8 , 12 ) ;
解答例を見る class Rectangle {
int width;
int height;
// コンストラクタ1:引数なし
Rectangle() {
this(10, 10); // コンストラクタ3を呼ぶ
}
// コンストラクタ2:一辺のみ指定(正方形)
Rectangle(int side) {
this(side, side); // コンストラクタ3を呼ぶ
}
// コンストラクタ3:widthとheightを指定
Rectangle(int width, int height) {
this.width = width;
this.height = height;
System.out.println(width + "x" + height + "の長方形を作成しました");
}
int getArea() {
return width * height;
}
void showInfo() {
System.out.println("幅: " + width + ", 高さ: " + height + ", 面積: " + getArea());
}
}
public class Main {
public static void main(String[] args) {
Rectangle rect1 = new Rectangle();
rect1.showInfo();
System.out.println("---");
Rectangle rect2 = new Rectangle(5);
rect2.showInfo();
System.out.println("---");
Rectangle rect3 = new Rectangle(8, 12);
rect3.showInfo();
}
}
課題3: Employeeクラスの作成(バリデーション付き)
要件 :
Employee(従業員)クラスを定義する
フィールド:name(String)、age(int)、salary(int)
コンストラクタで全フィールドを受け取る
バリデーション:
名前が空またはnullの場合、"名無し"にする
年齢が0未満または150を超える場合、0にする
給料が負の場合、0にする
メソッド:showInfo()で全情報を表示
4人の従業員を作成し、正常なケースと異常なケースをテストする
ヒント :
Employee emp1 = new Employee ( "太郎" , 30 , 300000 ) ; Employee emp2 = new Employee ( "" , 25 , 250000 ) ; Employee emp3 = new Employee ( "次郎" , - 5 , 200000 ) ; Employee emp4 = new Employee ( "花子" , 28 , - 10000 ) ;
解答例を見る class Employee {
String name;
int age;
int salary;
Employee(String name, int age, int salary) {
// バリデーション:名前
if (name == null || name.isEmpty()) {
System.out.println("警告: 名前が空です。デフォルト値を設定します");
this.name = "名無し";
} else {
this.name = name;
}
// バリデーション:年齢
if (age < 0 || age > 150) {
System.out.println("警告: 年齢が不正です(" + age + ")。デフォルト値を設定します");
this.age = 0;
} else {
this.age = age;
}
// バリデーション:給料
if (salary < 0) {
System.out.println("警告: 給料が負です(" + salary + ")。デフォルト値を設定します");
this.salary = 0;
} else {
this.salary = salary;
}
System.out.println("従業員を作成しました\n");
}
void showInfo() {
System.out.println("名前: " + name + ", 年齢: " + age + "歳, 給料: " + salary + "円");
}
}
public class Main {
public static void main(String[] args) {
// 正常なケース
Employee emp1 = new Employee("太郎", 30, 300000);
emp1.showInfo();
System.out.println("---\n");
// 名前が空のケース
Employee emp2 = new Employee("", 25, 250000);
emp2.showInfo();
System.out.println("---\n");
// 年齢が負のケース
Employee emp3 = new Employee("次郎", -5, 200000);
emp3.showInfo();
System.out.println("---\n");
// 給料が負のケース
Employee emp4 = new Employee("花子", 28, -10000);
emp4.showInfo();
}
}
FAQ
Q1: コンストラクタに戻り値を書くとどうなる?
A1:
エラーになる。 コンストラクタには戻り値を書けない(voidも不可)。
エラーになる例:
class Person { String name ; void Person ( String name ) { this . name = name ; } }
エラーメッセージ:
error: invalid method declaration; return type required
理由 :
コンストラクタは特別なメソッドであり、戻り値の概念がない。
voidを書くと、コンパイラはこれを「普通のメソッド」と判断し、「クラス名と同じ名前のメソッド」として扱う。
Q2: コンストラクタを複数定義すると、どれが呼ばれるのか?
A2:
引数の型と個数が一致するコンストラクタが呼ばれる。
class Person {
String name;
int age;
Person() {
System.out.println("コンストラクタ1が呼ばれました");
this.name = "名無し";
this.age = 0;
}
Person(String name) {
System.out.println("コンストラクタ2が呼ばれました");
this.name = name;
this.age = 0;
}
Person(String name, int age) {
System.out.println("コンストラクタ3が呼ばれました");
this.name = name;
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person(); // コンストラクタ1
Person p2 = new Person("太郎"); // コンストラクタ2
Person p3 = new Person("花子", 20); // コンストラクタ3
}
}
実行結果:
コンストラクタ1が呼ばれました コンストラクタ2が呼ばれました コンストラクタ3が呼ばれました
Q3: this()の呼び出しを最初の行以外に書くとどうなる?
A3:
エラーになる。
エラーになる例:
class Person { String name ; int age ; Person ( ) { System . out . println ( "デフォルトコンストラクタ" ) ; this ( "名無し" , 0 ) ; } Person ( String name , int age ) { this . name = name ; this . age = age ; } }
エラーメッセージ:
error: call to this must be first statement in constructor
理由 :
コンストラクタの連鎖を正しく行うため、this()は最初の行でなければならない。
これにより、フィールドの初期化順序が保証される。
Q4: コンストラクタ内でインスタンスメソッドを呼んでも良いのか?
A4:
呼べるが、注意が必要。
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
introduce(); // コンストラクタ内でメソッドを呼ぶ
}
void introduce() {
System.out.println("私の名前は" + name + "で、" + age + "歳です");
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("太郎", 18);
}
}
実行結果:
注意点 :
コンストラクタ内でメソッドを呼ぶ場合、フィールドが初期化されていることを確認する
継承時は、親クラスのコンストラクタが先に実行されるため、思わぬバグが発生する可能性がある
Q5: コンストラクタをprivateにするとどうなる?
A5:
そのクラスの外からインスタンスを生成できなくなる。
class Singleton { private static Singleton instance = new Singleton ( ) ; private Singleton ( ) { System . out . println ( "インスタンスを作成しました" ) ; } public static Singleton getInstance ( ) { return instance ; } } Singleton s = Singleton . getInstance ( ) ;
これは Singletonパターン という設計パターンで、インスタンスを1つだけに制限したい場合に使う。
まとめ
この章では、コンストラクタ について学んだ。
学んだ内容
Step 0 : コンストラクタがないと、初期化を忘れたり、不完全な状態のインスタンスが存在する
Step 1 : コンストラクタはインスタンス生成時に自動的に呼ばれる特別なメソッドである
Step 2 : コンストラクタはクラス名と同じ名前で、戻り値がない
Step 3 : thisキーワードでフィールドと引数を区別する
Step 4 : デフォルトコンストラクタは自動で用意されるが、引数ありコンストラクタを定義すると用意されない
Step 5 : コンストラクタのオーバーロードで複数のコンストラクタを定義できる
Step 6 : this()で別のコンストラクタを呼び、初期化ロジックを集約できる
Step 7 : 必須フィールドの強制、バリデーション、イミュータブルオブジェクトなど、実践パターンを学んだ
Step 8 : 実践課題で、コンストラクタの設計と実装を体験した
次のステップ
次の章では、継承 について学ぶ。
既存のクラスを拡張して新しいクラスを作る方法を学び、コードの再利用性をさらに高める。
コンストラクタの説明として最も適切なものを選べ。
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
正解 D. オブジェクトが作られるときに自動で呼ばれる、初期化のための特別なメソッド
解説 コンストラクタは new でオブジェクトを作成するときに 自動的に呼び出される 特別なメソッドである。クラス名と同じ名前を持ち、戻り値の型を書かない。フィールドの初期化に使われることが多い。
問題2. コンストラクタとメソッドの違いを説明できる
コンストラクタと通常のメソッドの違いとして正しいものを選べ。
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
正解 D. コンストラクタはクラス名と同じ名前で、戻り値の型を書かない
解説 コンストラクタは①クラス名と同じ名前 を持つ、②戻り値の型を書かない (voidも書かない)、③ new のときに自動で呼ばれる、という特徴がある。
this キーワードの役割として正しいものを選べ。
ヒントを表示this は「自分自身のオブジェクト」を指すキーワードである。引数名とフィールド名が同じときに区別するために使われる。
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
正解 D. 自分自身のオブジェクトを指し、フィールドと引数を区別するために使う
解説 this は 自分自身のオブジェクト を指す。コンストラクタや setter で引数名とフィールド名が同じ場合、this.name = name; のように書いてフィールドと引数を区別する。staticメソッド内では使用できない。
問題4. コンストラクタでフィールドに初期値を設定できる
以下のコードの空欄を埋めて、引数なしコンストラクタでフィールドにデフォルト値を設定するプログラムを完成させよ。
class Person {
String name;
int age;
Person() {
;
;
}
}
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 this.name = "未設定"; this.age = 0;
解説 引数なしコンストラクタ内でフィールドにデフォルト値を設定する。this.name でフィールドを指定しているが、引数名と衝突しない場合は this. を省略してもよい。
以下のコードの空欄を埋めて、引数ありのコンストラクタを完成させよ。
class Person {
String name;
int age;
Person(
) {
;
;
}
}
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 String name, int age / this.name = name / this.age = age
解説 引数ありコンストラクタでは、引数で受け取った値をフィールドに設定する。this.name = name; で「このオブジェクトのnameフィールドに引数nameの値を代入する」という意味になる。
問題6. thisキーワードでフィールドを指定できる
以下のコードの空欄を埋めて、フィールドに値を設定するsetterメソッドを完成させよ。
class Product {
String name;
int price;
void setName(String name) {
= name;
}
}
ヒントを表示引数名 name とフィールド名 name が同じとき、this.name でフィールドを指定する。this がないと引数自身に代入してしまう。
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解説 引数名 name とフィールド名 name が同じ場合、this.name でフィールドを指定する。this を付けないと引数nameに引数nameを代入することになり、フィールドは変更されない。
Personクラスに以下の3つのコンストラクタを作成せよ。
要件 :
引数なし(name="未設定", age=0に初期化)
名前のみ(name=引数, age=0)
名前と年齢の両方
class Person {
String name;
int age;
// ここに3つのコンストラクタを書いてください
void showInfo() {
System.out.println("名前: " + name + ", 年齢: " + age);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person("田中");
Person p3 = new Person("佐藤", 25);
p1.showInfo();
p2.showInfo();
p3.showInfo();
}
} ヒントを表示コンストラクタも引数の数や型を変えて複数定義できる(オーバーロード)。引数なし版、名前のみ版、名前+年齢版のように段階的に作ろう。
解答を表示する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解説 解答例 :
class Person {
String name;
int age;
Person() {
this.name = "未設定";
this.age = 0;
}
Person(String name) {
this.name = name;
this.age = 0;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
コンストラクタのオーバーロードでは、引数の組み合わせを変えて複数のコンストラクタを定義できる。利用者は必要な情報だけを渡してオブジェクトを作成できる。
問題8. デフォルトコンストラクタの仕組みを説明できる
デフォルトコンストラクタについて正しい説明を選べ。
ヒントを表示コンストラクタを1つも定義しない場合にのみ、Javaが自動で引数なしコンストラクタを提供する。1つでも自分で定義すると提供されなくなる。
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
正解 D. コンストラクタを1つも定義しない場合に、Javaが自動で提供する引数なしコンストラクタ
解説 デフォルトコンストラクタは、クラスにコンストラクタを 1つも定義しない場合にのみ Javaが自動で提供する。引数ありコンストラクタを1つでも定義すると、デフォルトコンストラクタは生成されない。その場合は引数なしコンストラクタも明示的に定義する必要がある。
問題9. this()で別のコンストラクタを呼び出せる
以下のコードの空欄を埋めて、引数なしコンストラクタから引数ありコンストラクタを呼び出すプログラムを完成させよ。
class Person {
String name;
int age;
Person() {
;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
ヒントを表示コンストラクタ内で this(引数) と書くと、同じクラスの別のコンストラクタを呼び出せる。コンストラクタの最初の行 でのみ使用可能である。
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解説 this(引数) を使うと、同じクラスの別のコンストラクタを呼び出せる。コードの重複を避けるために有効である。this() はコンストラクタの 最初の行 でしか使えない。
Personクラスのコンストラクタで、バリデーション付きの初期化を実装せよ。
要件 :
年齢が0未満の場合は IllegalArgumentException を投げる
名前が空文字の場合は「名無し」をデフォルト値に設定する
class Person {
String name;
int age;
Person(String name, int age) {
// ここにバリデーション付きの初期化を書いてください
}
void showInfo() {
System.out.println("名前: " + name + ", 年齢: " + age);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("田中", 25);
p1.showInfo();
Person p2 = new Person("", 30);
p2.showInfo();
try {
Person p3 = new Person("佐藤", -5);
} catch (IllegalArgumentException e) {
System.out.println("エラー: " + e.getMessage());
}
}
} ヒントを表示コンストラクタ内でif文を使って引数の値をチェックし、不正な値の場合は例外を投げるか、デフォルト値を設定する。
解答を表示する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解説 解答例 :
class Person {
String name;
int age;
Person(String name, int age) {
if (age < 0) {
throw new IllegalArgumentException("年齢は0以上である必要があります");
}
if (name.isEmpty()) {
this.name = "名無し";
} else {
this.name = name;
}
this.age = age;
}
}
コンストラクタでバリデーションを行うことで、不正な状態のオブジェクトが作られることを防げる。値のチェックはカプセル化の一部でもあり、データの整合性を保つために重要である。