1.クラスとインスタンス
学習目標
- クラスとインスタンスの関係を説明できる
- フィールド・コンストラクター・メソッドを持つクラスを定義できる
newでインスタンスを生成し、フィールドの読み書きとメソッド呼び出しができる
1. クラス
Section titled “1. クラス”書籍ならタイトル・価格・在庫、ユーザーなら名前・メールアドレス・年齢、注文なら商品・数量・日時。プログラムはこのような複数の属性を持つデータを扱います。Java には int、double、String といった型が組み込まれていますが、これらが表すのは単一の値です。「タイトルと価格と在庫を持つ書籍」のように複数の属性を 1 つに束ねた型は、組み込み型には存在しません。
1-1. クラスの定義
Section titled “1-1. クラスの定義”クラス は、こうした新しい型を自分で定義する仕組みです。データ(フィールド)と処理(メソッド)をまとめて 1 つの型として扱えます。
クラスは class キーワードで定義し、クラスが持つデータを フィールド として データ型 フィールド名; の形で並べます。
class クラス名 { データ型 フィールド名; ...}public class Person { String name; int age;}これで Person という新しい型を定義しました。Person は name(文字列)と age(整数)の 2 つのフィールドを持ちます。public を付けると、このクラスは別のパッケージからも参照できます。
新しく作った型は、int や String と同じように扱えます。Person 型の変数の宣言や、Person[] のような配列の宣言が可能です。
クラスを定義しただけでは値を扱えません。Person 型の値を使うには、Person クラスから具体的な実体を生成する必要があります。
2. インスタンス
Section titled “2. インスタンス”2-1. クラスとインスタンスの関係
Section titled “2-1. クラスとインスタンスの関係”クラスから生成された実体を インスタンス と呼びます。オブジェクト も同義の用語です。
クラスは型の設計図、インスタンスはその設計図から生成される実体です。
設計図は 1 つでも、そこから生成するインスタンスはいくつでも作れます。同じ Person クラスから生成された 2 つのインスタンスは、それぞれが独立した name と age の値を持ちます。
2-2. インスタンスの生成
Section titled “2-2. インスタンスの生成”クラスからインスタンスを生成するには new 演算子を使います。
new クラス名()Person を利用するコードは別のクラスに記述します。
public class Main { public static void main(String[] args) { Person p = new Person(); // ① インスタンスを生成し、参照を p に代入 p.name = "田中"; // ② インスタンスの name フィールドに代入 p.age = 25; // ③ インスタンスの age フィールドに代入
System.out.println(p.name); System.out.println(p.age); }}田中25new Person() で、Person 型のインスタンスが 1 つ生成されます。
以降のコード例では、Main.java の main メソッドの中身だけを示します。
2-3. 複数のインスタンス
Section titled “2-3. 複数のインスタンス”同じクラスから複数のインスタンスを生成でき、それぞれが独立したフィールドの値を持ちます。
Person p1 = new Person();p1.name = "田中";p1.age = 25;
Person p2 = new Person();p2.name = "鈴木";p2.age = 30;
p1.name = "中村";System.out.println(p1.name); // 中村System.out.println(p2.name); // 鈴木new Person() を 2 回実行すると、別々のオブジェクトがメモリ上に配置されます。p1 と p2 はそれぞれ別のオブジェクトを参照するため、p1.name を変更しても p2.name には影響しません。
3. コンストラクター
Section titled “3. コンストラクター”ここまでの例では、インスタンスを生成してから 1 つずつフィールドに代入していました。
Person p = new Person();p.name = "田中";p.age = 25;この書き方では、new Person() の実行から各フィールドへの代入が完了するまでの間、name = null、age = 0 のフィールドを持つ不完全な Person インスタンスが存在します。インスタンスを完成させる責任は呼び出し側のコードにあります。
コンストラクター は、インスタンスの生成と初期化を 1 つの操作にまとめる仕組みです。
3-1. コンストラクターの定義
Section titled “3-1. コンストラクターの定義”コンストラクターはクラス名と同じ名前で定義します。戻り値の型は書きません。
class クラス名 { クラス名(引数) { 初期化の処理 }}public class Person { String name; int age;
public Person(String name, int age) { this.name = name; this.age = age; }}Person p = new Person("田中", 25);System.out.println(p.name); // 田中System.out.println(p.age); // 25new Person("田中", 25) を実行したときの流れを追います。
Person型のオブジェクトがメモリ上に生成される- コンストラクターが呼び出され、引数
nameに"田中"、ageに25が渡る - コンストラクターの中で
this.name = nameとthis.age = ageが実行され、インスタンスのフィールドが初期化される - 完成したオブジェクトへの参照が返り、変数
pに代入される
3-2. this キーワード
Section titled “3-2. this キーワード”コンストラクターの中の this.name = name は、インスタンス自身のフィールドに引数の値を代入する文です。
引数名とフィールド名が同じ name なので、どちらを指すかを区別する必要があります。this は、コンストラクターやメソッドが呼び出されている対象のインスタンスを指すキーワードです。new Person("田中", 25) の場合、コンストラクター内の this はこの new で生成された Person のインスタンスを指します。
| 表記 | 意味 |
|---|---|
this.name | インスタンスのフィールド name |
name | コンストラクターの引数 name |
this. を書いた場合と書き忘れた場合の挙動を比較します。
public Person(String name, int age) { this.name = name; this.age = age;}Person p = new Person("田中", 25);System.out.println(p.name); // 田中System.out.println(p.age); // 25左辺の this.name はインスタンスのフィールド、右辺の name は引数を指すため、引数の値がフィールドに代入されます。
public Person(String name, int age) { name = name; // 引数 name に引数 name を代入しているだけ age = age;}Person p = new Person("田中", 25);System.out.println(p.name); // nullSystem.out.println(p.age); // 0左辺と右辺の両方が引数 name を指すため、フィールドへの代入は行われません。フィールドは初期値(null と 0)のままです。
3-3. デフォルトコンストラクター
Section titled “3-3. デフォルトコンストラクター”インスタンスの生成 では、コンストラクターを定義していない Person に対して new Person() のように引数なしで生成できました。これは Java が デフォルトコンストラクター(引数なしで何もしないコンストラクター)を暗黙に提供していたためです。コンストラクターを 1 つでも自分で定義すると、このデフォルトは無効になります。
public Person(String name, int age) を定義した Person に対して、new Person() を書くとコンパイルエラーになります。
Person p = new Person(); // コンパイルエラー:引数の数が合わないこれにより、name と age を渡さずに Person を生成する方法はなくなります。フィールドが初期値のまま残ることを、Java の仕組みが防ぎます。
4. メソッド
Section titled “4. メソッド”クラスには、データに加えて メソッド(処理)も定義できます。
4-1. メソッドの定義
Section titled “4-1. メソッドの定義”メソッドはクラスの中で次の形で定義します。
class クラス名 { 戻り値の型 メソッド名(引数) { 処理 return 戻り値; }}戻り値がない場合は型として void を指定し、return 文は不要です。
例として、自己紹介を表示する introduce メソッドを Person に追加します。
public class Person { String name; int age;
public Person(String name, int age) { this.name = name; this.age = age; }
void introduce() { System.out.println("私は" + name + "、" + age + "歳です"); }}メソッド内ではフィールドに直接アクセスできます。引数と名前が衝突しない限り、this. を付けないのが Java の慣習です。
4-2. メソッドの呼び出し
Section titled “4-2. メソッドの呼び出し”メソッドはインスタンスに対して呼び出します。
Person p1 = new Person("田中", 25);Person p2 = new Person("鈴木", 30);
p1.introduce();p2.introduce();私は田中、25歳です私は鈴木、30歳ですp1.introduce() は「p1 のインスタンスに対して introduce メソッドを呼び出す」という意味です。メソッド内で参照される name と age は p1 のフィールドの値であるため、出力には 田中 と 25 が現れます。p2.introduce() も同様に、p2 のフィールドが参照されます。