Java入門 STEP10|コンストラクタを使ってみよう

karin@taishi@felmia

コンストラクタとは?

STEP9では、Studentオブジェクトを作ったあとに、名前と点数を設定しました。

Student student = new Student();

student.name = "Lumy";
student.score = 80;

まず、

new Student()

でオブジェクトを作り、そのあとにnamescoreへ値を代入しています。

この方法でもStudentオブジェクトを作ることはできます。

しかし、

「Studentを作るときに、名前と点数も一緒に設定したい」

という場合はどうすればよいでしょうか。

Javaでは、オブジェクトを作るときに最初の値を設定するために、「コンストラクタ」を使うことができます。

コンストラクタを使うと、

Student student = new Student("Lumy", 80);

のように、オブジェクトを作るときに値を渡すことができます。

コンストラクタを作ってみよう

それでは、STEP9で作ったStudentクラスにコンストラクタを追加してみましょう。

Studentクラスを次のように変更してください。

public class Student {

    String name;
    int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public void introduce() {
        System.out.println("名前:" + name);
        System.out.println("点数:" + score);
    }

}

新しく追加したのが、この部分です。

public Student(String name, int score) {
    this.name = name;
    this.score = score;
}

これがコンストラクタです。

普通のメソッドとは何が違うの?

コンストラクタはメソッドと見た目が似ていますが、大きな特徴があります。

コンストラクタの特徴

コンストラクタの名前
クラス名と同じ名前にする

今回なら、

クラス名 → Student

コンストラクタ名 → Student

となります。

また、通常のメソッドにあるvoidintなどの戻り値の型を書きません。

public Student(String name, int score)

のように書きます。

コンストラクタを使ってオブジェクトを作ろう

次に、STEP9で作ったStudentSampleクラスを変更します。

public class StudentSample {

    public static void main(String[] args) {
        Student student = new Student("Lumy", 80);

        student.introduce();
    }

}

実行結果

名前:Lumy
点数:80

STEP9では、

Student student = new Student();

student.name = "Lumy";
student.score = 80;

と書いていました。

今回は、

Student student = new Student("Lumy", 80);

だけで、オブジェクトを作ると同時に名前と点数を設定しています。

値が渡される流れ

new Student("Lumy", 80)

とすると、コンストラクタの、

public Student(String name, int score)

へ値が渡されます。

渡した値コンストラクタで受け取る
"Lumy"String name
80int score

これはSTEP7で学んだ引数と同じ考え方です。

コンストラクタはnewしたときに呼び出される

new Student("Lumy", 80);

Studentのコンストラクタが呼び出される

"Lumy"80を受け取る

Studentオブジェクトの名前と点数を設定する

コンストラクタは、オブジェクトを作るときの初期設定をするために使うと考えると分かりやすいです。

ルミィ
ルミィ

new Student("Lumy", 80)だけで、作るときに名前と点数を渡せるようになったね♪
コンストラクタは「オブジェクトを作るときの初期設定」と考えてみよう!

thisって何?

先ほど作ったコンストラクタには、次の処理がありました。

public Student(String name, int score) {
    this.name = name;
    this.score = score;
}

ここを見ると、

this.name = name;

のように、nameという同じ名前が左右に登場しています。

しかし、この2つのname同じものを表しているわけではありません。

左側のthis.name

this.nameは、このStudentオブジェクトが持っているnameフィールドを表しています。

STEP9で作ったStudentクラスには、

String name;
int score;

というフィールドがありました。

this.namenameは、このフィールドを指しています。

同じように、

this.score

はStudentオブジェクトが持っているscoreフィールドです。

右側のname

一方、右側のnameは、コンストラクタの引数です。

ここを見てみましょう。

public Student(String name, int score)

String nameint scoreで、newするときに渡された値を受け取っています。

例えば、

new Student("Lumy", 80);

とすると、

name"Lumy"

score80

となります。

this.name = nameを分解してみよう

つまり、

this.name = name;

は、

「引数nameで受け取った値を、このStudentオブジェクトのnameフィールドに代入する」

という意味です。

scoreも同じです。

書き方意味
this.nameこのオブジェクトのnameフィールド
nameコンストラクタで受け取った引数
this.scoreこのオブジェクトのscoreフィールド
scoreコンストラクタで受け取った引数

値の流れも確認してみましょう。

new Student("Lumy", 80)

コンストラクタが"Lumy"80を受け取る

name"Lumy"が入る
score80が入る

this.name = name;
→ オブジェクトのname"Lumy"を保存

this.score = score;
→ オブジェクトのscore80を保存

Studentオブジェクトが、

name → Lumy
score → 80

という情報を持つ

なぜthisを付けるの?

今回のように、フィールドと引数が同じ名前の場合、それらを区別するためにthisを使います。

例えば、

String name;

public Student(String name) {
    this.name = name;
}

左側のthis.name
→ フィールド

右側のname
→ 引数

と区別できます。

thisを付ける側を間違えないようにしよう

this.name = name;

は、

引数の値 → フィールド

へ代入しています。

「右側の値を左側へ代入する」という、これまでの代入と同じです。

thisが付いているからといって、代入の方向が変わるわけではありません。

thisは「このオブジェクト」

thisは、簡単にいうと「このオブジェクト自身」を表します。

例えば、

Student student1 = new Student("Lumy", 80);
Student student2 = new Student("Java", 90);

とした場合、それぞれのオブジェクトを作るときにコンストラクタが呼ばれます。

そのときのthisは、今作っているStudentオブジェクト自身を表します。

そのため、それぞれ別のnamescoreを持つことができます。

ルミィ
ルミィ

this.name = nameは見た目がちょっとややこしいね!
「このオブジェクトのnameに、受け取ったnameを入れる」と読むと分かりやすいよ♪

コンストラクタは複数作ることができる

ここまでは、名前と点数を受け取るコンストラクタを使ってきました。

public Student(String name, int score) {
    this.name = name;
    this.score = score;
}

しかし、Studentオブジェクトを作るときに、必ず名前と点数の両方が決まっているとは限りません。

例えば、「名前は分かっているけれど、点数はまだ決まっていない」という場合も考えられます。

Javaでは、引数の数やデータ型が異なれば、同じ名前のコンストラクタを複数作ることができます。

名前だけを受け取るコンストラクタを追加しよう

先ほどのStudentクラスを次のように変更してください。

public class Student {

    String name;
    int score;

    public Student(String name) {
        this.name = name;
    }

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public void introduce() {
        System.out.println("名前:" + name);
        System.out.println("点数:" + score);
    }

}

これでStudentクラスには、2つのコンストラクタが用意されました。

Student(String name)

名前だけを受け取ります。

Student(String name, int score)

こちらは名前と点数を受け取ります。

このように、同じ名前で引数の異なるものを複数用意することを「オーバーロード」と呼びます。

2つのコンストラクタを使ってみよう

StudentSampleクラスを次のように変更してください。

public class StudentSample {

    public static void main(String[] args) {
        Student student1 = new Student("Lumy");
        Student student2 = new Student("Java", 90);

        student1.introduce();
        student2.introduce();
    }

}

実行結果

名前:Lumy
点数:0
名前:Java
点数:90

student1では、

new Student("Lumy")

と名前だけを渡しているため、Student(String name)のコンストラクタが使われます。

一方、student2では、

new Student("Java", 90)

と2つの値を渡しているため、Student(String name, int score)のコンストラクタが使われます。

点数が0になったのはなぜ?

student1には名前しか設定していません。

それでも実行結果を見ると、点数には0が入っています。

Javaでは、フィールドに最初の値を設定しなかった場合、データ型に応じた初期値が入ります。

今回のscoreint型なので、初期値は0です。

コンストラクタのオーバーロード

引数を変えることで、同じクラスに複数のコンストラクタを用意できます。

今回なら、

new Student("Lumy")

→ 名前だけ設定する

new Student("Java", 90)

→ 名前と点数を設定する

というように、オブジェクトを作るときの状況に合わせて使い分けることができます。

ルミィ
ルミィ

渡した値に合わせて、使われるコンストラクタが変わるんだね♪
「名前だけ分かっているとき」みたいな作り方も用意できるよ!

引数なしのコンストラクタが使えなくなった?

STEP9では、Studentオブジェクトを次のように作っていました。

Student student = new Student();

ところが、現在のStudentクラスで同じように書くとエラーになります。

なぜでしょうか。

コンストラクタを書かなかった場合


STEP9のStudentクラスには、自分で作ったコンストラクタがありませんでした。

public class Student {

    String name;
    int score;

}

このコードを見ると、Student()というコンストラクタはどこにも書かれていません。
しかしJavaでは、コンストラクタを1つも書かなかった場合、引数なしのコンストラクタが自動的に使える状態になります。
イメージとしては、Javaが内部的に次のようなコンストラクタを用意してくれていると考えてください。

public Student() {
}

このコードがStudentクラスに実際に追加されて表示されるわけではありません。

自分でコンストラクタを書いていない場合に、Javaがこのような引数なしのコンストラクタがあるものとして扱ってくれるということです。

そのため、STEP9では、

Student student = new Student();

と書いてStudentオブジェクトを作ることができました。

このように、自分でコンストラクタを1つも定義していないときに自動的に用意されるコンストラクタを、「デフォルトコンストラクタ」と呼びます。

自分でコンストラクタを作るとどうなる?

STEP10では、次のようなコンストラクタを自分で作りました。

public Student(String name) {
    this.name = name;
}

このようにコンストラクタを1つでも自分で定義すると、デフォルトコンストラクタは自動では用意されません。

そのため、

Student student = new Student();

と書いても、引数なしで呼び出せるコンストラクタが存在しないためエラーになります。

コンストラクタを追加したら、以前のnewがエラーになった?

コンストラクタを1つも書いていない

new Student()が使える

自分で引数ありのコンストラクタを作った

new Student()は自動では使えなくなる

「コンストラクタを追加したら、今までのnew Student()がエラーになった」という場合は、Studentクラスにどのコンストラクタがあるか確認してみましょう。

new Student()も使いたい場合は?

引数なしでもStudentオブジェクトを作れるようにしたい場合は、引数なしのコンストラクタも自分で作ります。

現在のStudentクラスに、次のコンストラクタを追加できます。

public Student() {
}

これで、

Student student1 = new Student();
Student student2 = new Student("Lumy");
Student student3 = new Student("Java", 90);

という3種類の作り方ができるようになります。

引数なしでnewできるかは、コンストラクタを確認しよう

new Student()

と書けるのは、引数なしで呼び出せるコンストラクタがある場合です。

Javaがいつでも自動的にStudent()を用意してくれるわけではありません。

自分でコンストラクタを1つも定義していない場合に、デフォルトコンストラクタが自動的に用意されます。

ルミィ
ルミィ

「さっきまでnew Student()で動いてたのに!」ってなったら、コンストラクタを追加していないか確認してみよう♪

よくある間違い

コンストラクタは普通のメソッドと書き方が似ているため、最初は混同しやすい部分です。

エラーになったときは、次のポイントを確認してみましょう。

コンストラクタの名前がクラス名と違う

コンストラクタの名前は、クラス名と同じ名前にする必要があります。

例えば、クラス名がStudentなら、

public Student(String name) {
    this.name = name;
}

と書きます。

クラス名と違う名前にすると、Studentクラスのコンストラクタにはなりません。

コンストラクタ名はクラス名と同じ

クラス名が、

Student

なら、コンストラクタも、

Student

です。

大文字・小文字も区別されるので注意しましょう。

voidを書いてしまう

コンストラクタには、voidintなどの戻り値の型を書きません。

次の書き方を比べてみましょう。

public Student(String name) {
    this.name = name;
}

これはStudentクラスのコンストラクタです。

一方、次のようにvoidを付けると意味が変わります。

public void Student(String name) {
    this.name = name;
}

これはコンストラクタではなく、Studentという名前のメソッドとして扱われます。

見た目がよく似ているので注意しましょう。

newするときの引数が合っていない

例えば、Studentクラスに次のコンストラクタがあるとします。

public Student(String name, int score) {
    this.name = name;
    this.score = score;
}

このコンストラクタを使う場合は、

Student student = new Student("Lumy", 80);

のように、String型とint型の値を順番に渡します。

引数の数やデータ型が合っていないと、そのコンストラクタを呼び出すことができません。

STEP7で学んだメソッドの引数と同じように、数・データ型・順番を確認しましょう。

thisを付ける場所を間違える

次の処理も、最初は間違えやすいところです。

this.name = name;

this.nameこのオブジェクトのフィールド、右側のnameコンストラクタで受け取った引数でした。

つまり、

引数で受け取った値 → オブジェクトのフィールド

へ代入しています。

this.name = name;

を見たら、

「このオブジェクトのnameに、引数のnameを代入する」

と読んでみましょう。

右側の値を左側へ代入するというルールは、これまでの代入と同じです。

コンストラクタを追加したあとにnew Student()を使っている

自分で引数ありのコンストラクタを作ると、引数なしのデフォルトコンストラクタは自動では用意されません。

例えば、Studentクラスに、

public Student(String name) {
    this.name = name;
}

だけがある場合、

Student student = new Student();

とは書けません。

引数なしでも作れるようにしたい場合は、自分で引数なしのコンストラクタも用意します。

public Student() {
}
ルミィ
ルミィ

コンストラクタで迷ったら、「クラス名と同じ?」「voidを付けてない?」「引数は合ってる?」を確認してみよう♪

STEP10のまとめ

このSTEPでは、オブジェクトを作るときに使われる「コンストラクタ」について学びました。

最後に、今回のポイントを振り返っておきましょう。

  • コンストラクタは、オブジェクトを作るときに呼び出される
  • オブジェクトを作るときの初期設定に利用できる
  • コンストラクタの名前はクラス名と同じにする
  • コンストラクタにはvoidintなどの戻り値の型を書かない
  • 引数を使って、オブジェクトを作るときに値を渡すことができる
  • thisは、そのオブジェクト自身を表す
  • this.nameのように書くことで、オブジェクトのフィールドを表すことができる
  • 引数の数やデータ型が異なれば、コンストラクタを複数作ることができる
  • このように、引数の異なるコンストラクタを複数定義することを「コンストラクタのオーバーロード」と呼ぶ
  • コンストラクタを1つも書かなかった場合は、引数なしのデフォルトコンストラクタが自動的に使える
  • 自分でコンストラクタを作ると、デフォルトコンストラクタは自動では用意されない

コンストラクタの流れを確認しよう

今回使ったコードを、もう一度確認してみましょう。

Student student = new Student("Lumy", 80);

この1行から、次のような流れでStudentオブジェクトが作られます。

new Student("Lumy", 80)でオブジェクトを作る

② Studentのコンストラクタが呼び出される

public Student(String name, int score) {
    this.name = name;
    this.score = score;
}

③ 引数で値を受け取る

name"Lumy"
score80

④ 受け取った値をフィールドに保存する

this.name = name;
this.score = score;

⑤ 名前と点数を持ったStudentオブジェクトが使えるようになる

STEP9では、

「クラスからオブジェクトを作る」

ことを学びました。

STEP10では、そこから一歩進んで、

「オブジェクトを作るときに、必要な情報も設定する」

ことができるようになりました。

ルミィ
ルミィ

STEP10クリア!
newしたときにコンストラクタが呼ばれて、オブジェクトの最初の状態を作ってくれるんだね♪

次のSTEPへ

現在のStudentクラスでは、

String name;
int score;

とフィールドを作っています。

そのため、Studentクラスの外から、

student.score = -100;

のような値を直接入れることもできてしまいます。

点数として考えると、-100はおかしな値ですね。

では、勝手にフィールドを書き換えられないようにするにはどうすればよいのでしょうか?

次のSTEPでは、privateを使ってフィールドを外部から直接変更できないようにし、必要に応じてgettersetterを使って値を扱う方法を学びます。

STEP11「カプセル化を学ぼう」

記事URLをコピーしました