インスタンスを作る
インスタンスを作る とは
クラスから実体 (インスタンス) を作る方法と new 演算子の使い方を学ぼう。本レッスンでは、インスタンスを作る の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
インスタンスを作る
前のレッスンまでで、Java ではすべてのコードが class の中に入ること、そして public static を付けたメソッドはクラス名から直接呼び出せることを学びました。今回からはいよいよ、クラスから インスタンス (instance) を作って使う、オブジェクト指向の入り口に踏み込みます。
インスタンスとは何か
クラスは「設計図」、インスタンスは「設計図から作られた実体」です。たとえば「Book というクラス」は本そのものではなく、「本というものはどんな属性 (タイトル / 著者) と振る舞い (読む / しおりを挟む) を持つか」を書いた設計図に過ぎません。実際に本棚に並ぶ 1 冊 1 冊が インスタンス です。
身近なたとえで言うと、たい焼きの型 と たい焼き本体 の関係に近いです。型 (クラス) は 1 つしかありませんが、その型を使えば、あんこ入り、クリーム入り、白いたい焼き、と何個でも別々のたい焼き (インスタンス) を焼くことができます。
「クラス = 設計図、インスタンス = 実体」というフレーズはこの先 100 回くらい登場します。最初のうちはピンとこなくて当然なので、まずは「
newを 1 回押すたびに 1 個実体が生まれる」とだけ覚えておけば十分です。
クラスとインスタンスの関係を図にすると次のとおりです。1 つの Book クラスから、別々のインスタンスがいくつも生まれているのが分かります。
new 演算子で実体を作る
インスタンスを作るには、new という専用の演算子を使います。書き方はとてもシンプルです。
Java
new Book();たったこれだけで、Book クラスを基にした新しいインスタンスが 1 つメモリ上に生まれます。Book() の部分はコンストラクタの呼び出しで、引数を取ることもできますが、今回はまず 引数なし の最もシンプルな形を扱います。
ただし、これだけでは作ったインスタンスをすぐ捨ててしまうのと同じです。せっかく作った実体に名前を付けてあげないと、後から触ることができません。そこで登場するのが 変数への代入 です。
変数に代入してアクセスする
作ったインスタンスは、必ず変数に入れて使います。書き方は次のとおりです。
Java
Book b = new Book();
String message = b.read();左から右に向かって、3 つのパートに分かれているのが見えますか。型 Book、変数名 b、そして = new Book(); で実体を作って代入しています。これで b という名前を通して、いつでも先ほどの Book インスタンスにアクセスできるようになりました。
Book b—Book型の変数bを宣言する (まだ中身は空)new Book()— 新しいBookインスタンスを 1 つ作る=で両者を結ぶ — 変数bがそのインスタンスを指すようになる
「型を 2 回書いてるみたい」と感じるかもしれません。左の
Bookは「この変数にはこれからBookを入れますよ」という宣言、右のBook()は「実際にBookを作りますよ」という命令で、役割が違います。書き慣れると体が勝手に覚えます。
インスタンスに紐づくメソッドを呼び出すときは、変数名の後ろにドットを付けて b.read() のように書きます。これは「b が指している Book インスタンスの read を呼んでください」という意味です。static メソッドのときに使った Solution.helloWorld() のクラス名・ドット・メソッド名のリズムと、見た目はとても似ていますが、左側にあるのが クラス名 か 変数名 かで意味が大きく変わります。
1 つのクラスから複数のインスタンスを作る
クラスは設計図なので、同じクラスから複数のインスタンスを作ることができます。たとえば次のように書くと、別々の Book が 3 つ生まれます。
Java
Book b1 = new Book();
Book b2 = new Book();
Book b3 = new Book();b1 b2 b3 はそれぞれ別の実体です。b1 の中身を書き換えても、b2 b3 には影響しません。「同じクラスから生まれた別のインスタンス」というのは、双子の兄弟のような関係に近いかもしれません。同じ設計図から生まれているけれど、それぞれが独立した存在です。
インスタンスはメモリ上に作られます。
newするたびに新しい場所にデータが確保され、変数はその場所を指し示す参照を持ちます。最初は深く考えなくて大丈夫ですが、「newの回数 = メモリ上に生まれる実体の数」とだけ覚えておきましょう。
Solution の中に Book クラスを書く
chotdekiru の Java Playground では 1 つの Solution.java の中にコードを書きます。別ファイルを作る代わりに、Solution クラスの中に Book をネストして書くのが一番手軽です。書き方は次の 2 通りがあります。
まずは static を付けて書く static inner class パターンです。これは外側のクラスのインスタンスがなくても使えるので、coding 問題ではこれが鉄板です。
Java
public class Solution {
static class Book {
String read() {
return "Hello, Object!";
}
}
public static String instantiateAndGet() {
Book b = new Book();
return b.read();
}
}もう 1 つの書き方は、static を付けない通常の inner class です。こちらは外側のインスタンスとセットで使う前提なので、static メソッドからは少し扱いづらく、最初のうちは避けて構いません。
Java
public class Solution {
class Book {
String read() {
return "Hello, Object!";
}
}
}細かい話ですが、Java 公式の教科書ではトップレベルの別ファイルでクラスを書くのが王道です。
static inner classは、chotdekiru のように 1 ファイルで完結させたいときに便利な書き方として覚えておくとよいです。
よくある間違い
インスタンス化まわりで最初によくつまずく落とし穴を 3 つ紹介します。
newを書き忘れる —Book b = Book();のようにnewを抜いてしまうと、「Bookという名前のメソッドを呼ぼうとした」と解釈されてコンパイルエラーになります。インスタンスを作るときは必ずnewを先頭に付けてください- 変数宣言と
newを混同する —Book b;だけで終わってしまうと、変数bは宣言されていますが中身はnullのままです。この状態でb.read()を呼ぶと実行時にNullPointerExceptionが飛んできます。必ず= new Book();まで書ききりましょう staticメソッドをインスタンスから呼ぼうとする —Solution.helloWorld()のようなstaticメソッドは、本来クラス名から呼ぶものです。インスタンスを作ってs.helloWorld()と書いてもエラーにはなりませんが、警告が出るうえに意味も薄れます。staticはクラス、それ以外はインスタンス、と使い分けましょう
もう 1 つ、初心者を混乱させがちなのが「クラス名と変数名がそっくり」問題です。Book book = new Book(); のように、型 Book と変数名 book は別物ですが、書く側はつい同じものに見えてしまいます。Java では「型 → 変数名 → 値」の順に並ぶ、というリズムを意識すると整理しやすくなります。
エラーメッセージの中でも
NullPointerExceptionは Java エンジニアが一生付き合うことになる相棒です。出てきたら「どの変数がnullのまま使われたのか」を真っ先に疑うクセを今のうちから付けておきましょう。
やってみよう
それでは課題に挑戦しましょう。手順は次のとおりです。
- 右側のエディタを開く
Solutionクラスの中にstatic class Bookを書き、その中にString read()メソッドを定義するinstantiateAndGetメソッドの中でBook b = new Book();のようにインスタンスを作るreturn b.read();のように呼び出した結果を返す- 「実行」ボタンを押してテストが緑になることを確認する
慣れてきたら、Book インスタンスを 2 個 3 個と増やしてみたり、Book クラスにフィールド (String title) を追加してみたり、自由に遊んでみてください。次のレッスンからはこのインスタンスにフィールドとコンストラクタを持たせて、よりリアルな「設計図と実体」の関係に踏み込んでいきます。
クラスとインスタンスは Java の中心テーマです。ここでつまずいても焦らず、new を押すたびに新しい実体が生まれているイメージを大事にしながら、何度も手を動かして体に馴染ませていきましょう。
よくある質問
Q. クラスとインスタンスの違いは?
A. クラスは設計図、インスタンスは設計図から作った具体的なオブジェクトです。Person クラスから new Person('Alice', 20) でインスタンスを作ると、それぞれが別の name と age を持ちます。クラスは 1 つでもインスタンスは何個でも作れます。
Q. インスタンスを作る new は何をしていますか?
A. メモリを確保し、コンストラクタを呼び出し、初期化されたオブジェクトの参照を返します。Java/JavaScript は new 必須、Python は new なしで Person() と呼ぶだけ(内部的に new + init が走る)です。
Q. 1 つのクラスから複数のインスタンスを管理するには?
A. ArrayList / 配列 / Map に格納するのが定石です。各インスタンスは独立した状態を持つので、ループで for (Product p : products) のように回せます。集合操作(合計、最大値)は Stream API(Java)/ map・reduce(JS)が便利です。
次のレッスン
次は コンストラクタ で、クラスから実体 (インスタンス) を作る方法と new 演算子の使い方を学ぼう を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- インスタンス化 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. インスタンス化 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
Solutionクラスの中にBookクラスをネストで定義すること (static class Book推奨)Bookクラスにread()のような戻り値がStringのメソッドを持たせ、"Hello, Object!"を返すことinstantiateAndGet()の中でnew Book()でインスタンスを作り、その戻り値をreturnで返すこと
入出力例
test-cases.txt
instantiateAndGet() → "Hello, Object!"