こんにちは、かつコーチです。
今回は、Javaの学習で最初につまずきやすい「クラス」と「オブジェクト」の違いについて解説します。
「なんとなく分かった気がするけど、いざコードを書くと混乱する」という方は多いです。
この記事を読めば、設計図と実体の関係がスッキり理解できるようになります。
クラスとオブジェクトとは?
クラスは「設計図」
クラスとは、オブジェクトを作るための設計図のことです。
「どんなデータ(フィールド)を持ち、どんな動作(メソッド)ができるか」を定義します。
例えば「犬」というクラスを考えてみましょう。
public class Dog {
// フィールド(データ)
String name;
int age;
// メソッド(動作)
void bark() {
System.out.println(name + "が吠えました!");
}
}
このクラスはあくまで「犬とはこういうものだ」という定義に過ぎません。
まだ具体的な犬は1匹も存在していない状態です。
オブジェクトは「実体」
オブジェクトとは、クラスという設計図から実際に作られた実体のことです。
クラスからオブジェクトを作ることを「インスタンス化」と呼び、作られたオブジェクトは「インスタンス」とも呼ばれます。
public class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
dog1.name = "ポチ";
dog1.age = 3;
dog1.bark(); // ポチが吠えました!
Dog dog2 = new Dog();
dog2.name = "コロ";
dog2.age = 1;
dog2.bark(); // コロが吠えました!
}
}
同じDogクラスから、dog1とdog2という2つの別々のオブジェクトが作られました。
それぞれが独立したnameとageを持っている点がポイントです。
クラスとオブジェクトの関係を整理する
「たい焼き」で考えるとイメージしやすい
Javaの学習では「たい焼き」の例え話がよく使われます。
- クラス = たい焼きの型
- オブジェクト = 型から焼き上がったたい焼きそのもの
同じ型(クラス)を使っても、あんこの量や焼き加減が違う複数のたい焼き(オブジェクト)ができるように、同じクラスから複数の独立したオブジェクトを作ることができます。
newキーワードの役割
オブジェクトを作るときはnewキーワードを使います。
Dog dog1 = new Dog();
この1行は「Dogクラスを元に新しいオブジェクトをメモリ上に生成し、その参照をdog1という変数に代入する」という意味です。dog1自体にオブジェクトの中身が入っているわけではなく、オブジェクトが存在する場所への「参照」が入っている点に注意してください。
よくあるつまずきポイント・エラー対処
クラスとインスタンスのフィールドを混同する
初心者がよく間違えるのが、クラス定義のフィールドと、実際のオブジェクトが持つ値を混同することです。
❌Before
public class Dog {
String name = "ポチ"; // すべての犬の名前が「ポチ」になってしまう前提で考えてしまう
}
public class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
Dog dog2 = new Dog();
dog2.name = "コロ";
// dog1.nameは初期値の「ポチ」のまま
// 「dog1もコロになるはず」と勘違いしてハマる人が多い
}
}
✅After
フィールドの初期値はあくまで「初期値」であり、オブジェクトごとに個別に上書きできることを意識しましょう。
public class Dog {
String name; // 初期値は設定せず、コンストラクタや代入で個別に設定する
}
public class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
dog1.name = "ポチ";
Dog dog2 = new Dog();
dog2.name = "コロ";
System.out.println(dog1.name); // ポチ
System.out.println(dog2.name); // コロ
}
}
私が実際にJavaを学び始めた頃、dog1とdog2が同じフィールドの初期値を共有していると勘違いし、「片方を変えたらもう片方も変わってしまう」というバグに悩まされたことがあります。
実際にはオブジェクトごとにメモリ上の別領域が確保されるため、dog1.nameとdog2.nameは完全に独立しています。
この感覚は、実際にデバッガでオブジェクトのメモリアドレス(参照)を確認すると腹落ちしやすいです。
NullPointerExceptionでハマる
オブジェクトをnewし忘れて変数を使おうとすると、実行時に以下のようなエラーが出ます。
Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "Dog.bark()" because "dog1" is null
これはDog dog1;と宣言しただけでnew Dog()をしておらず、dog1が「何も指していない状態(null)」のままメソッドを呼び出そうとしたために発生します。
変数を宣言しただけではオブジェクトは作られない、という点を必ず覚えておきましょう。
応用・一歩先の使い方
複数のオブジェクトを配列やリストで管理する
実務では、1つのクラスから複数のオブジェクトを作り、まとめて管理することがよくあります。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Dog> dogs = new ArrayList<>();
Dog dog1 = new Dog();
dog1.name = "ポチ";
dogs.add(dog1);
Dog dog2 = new Dog();
dog2.name = "コロ";
dogs.add(dog2);
for (Dog dog : dogs) {
dog.bark();
}
}
}
このように「同じ設計図から作った複数の実体をまとめて扱う」という発想は、オブジェクト指向プログラミングの基本であり、この先学ぶコレクションやコンストラクタの理解にもつながります。
まとめ
この記事のポイント
- クラスはオブジェクトを作るための設計図であり、フィールド(データ)とメソッド(動作)を定義する
- オブジェクトはクラスから
newによって作られた実体で、インスタンスとも呼ばれる - 同じクラスから作った複数のオブジェクトは、それぞれ独立したフィールドの値を持つ
- 変数を宣言しただけではオブジェクトは作られず、
newし忘れるとNullPointerExceptionが発生する
次に読むべき記事
クラスとオブジェクトの基本を理解したら、次はオブジェクトを作る際に初期値を設定する仕組みである「コンストラクタの基本とthis」を読んでみてください。
タグ: Java, 初心者向け, オブジェクト指向