🌱

newで魂が入る!?Javaのインスタンス化をキャラでイメージ!

に公開

はじめに:

Java初心者として学んだことを、自分なりにかみくだいてまとめた初心者向けの記事です。まだまだ試行錯誤中ですが、読みやすさを目指してがんばっています!

登場人物と設定

基本的な設定です。今回の話に登場していないキャラクターも含まれますが、コメントアウトされているキャラクターたちも和気あいあいと過ごしている設定だと思ってください。

登場人物と設定:ここをクリック

【登場人物】
Mainクラス (Main.java)

🤗mainさん :メソッド階級 / かなり特別な存在

  • 何かあったら、自分たちが何をすればいいかを教えてくれるとみんなから信頼されている。全てのクラスの中心となる存在。

Heroクラス (Hero.java)

🌱インスタンス君

  • インスタンス化されることで、nameage のようなフィールド(心)を持つ。
  • たまに増えてる。
  • 新しい属性(個性)を得て成長することができる。

🌙スタティックさん

  • クラス委員長。クラスに属する全てのインスタンスを監視している。
  • 常に存在しているため、インスタンスが増えても変わらない。静かで威厳のある性格。

😎ゲッター君

  • nameage などのプライベートなフィールドにアクセスして、値を取得する。
  • 周りから「リア充ゲッター」「ナンパ野郎」と思われている。

⚙️セッターさん

  • nameage のようなフィールドを変更(設定)する。

🌟voidちゃん

  • メソッドの中で、結果を返さず静かに物事を処理する。
  • フィールドの状態を変えたり、メソッドで確定したことを外の人に教えたりする(コンソールに表示)のが得意。

保健室 ( // or /**/ )

コメントアウトさん

  • コメントアウトという状態異常のキャラクターが回復するのを見守る係。
  • コメントアウトされても元気なキャラが多く、楽しく過ごしている。

【設定】
🌎JAVA宇宙の中の1つの星の中の物語(project_school/src/chapter_1/)
💫神のお告げで覚醒!
   🔸 "javac Main" でクラス替えが起こる。
     → クラスや仲間が増えたりする。
   🔸 "java Main" でクエスト実行!
     → メンバーたちが本来の力を発揮する。

量産型ヒーロー 【落ち込むインスタンス君】

🌱インスタンス君
  ヒーロークラスで”ブレイブ”って名前になったんだ!かっこいいでしょ!
🌙スタティックさん
  私はカウンターの係になったよ。
  カウント:1・・ブレイブ
  カウント:2・・ビクトール
  カウント:3・・
🌱インスタンス君
  ・・・・・・。
🌙スタティックさん
  (カウント10・・量産型ヒーローか・・)
🌟voidちゃん
  がんばって!レベルアップだよ!!
⚙️セッターさん
  オブジェクトごとに個性が出てくるはずだから!!
🌱インスタンス君
  そうだね、がんばる・・

インスタンス化とは

クラスからオブジェクト(実体)を作ること。
オブジェクト とは🤔?

まず作ってみる!
【Heroクラス】

Hero.java
public class Hero {
    // クラスのメンバ変数がいる(フィールド)
    String name;
    
    // コンストラクタで名前を初期化
    public Hero(String name) {
        this.name = name;
    }
	
    // 初期化されたnameを使って挨拶する
    public void greet() {
        System.out.println("こんにちは、僕は" + name + "!");
    }
}

【Mainクラス】

Main.java
public class Main {
    public static void main(String[] args) {
	    
        Hero h1 = new Hero("ブレイブ"); // ここでインスタンス化
        h1.greet(); // 「こんにちは、僕はブレイブ!」が出力される
    }
}

Heroクラスの解説:
まずHeroクラスという部屋がある

public class Hero {
    // まだ何もない
}

Heroクラスに必要なメンバーを入れる

public class Hero {
    String name; // フィールド
    public Hero(String name) {this.name = name;} // コンストラクタ
    public void greet() {System.out.println("こんにちは、僕は" + name + "!");} // メソッド
}

フィールドは String 型の変数 name の情報だけを持っている。
そして、クラスの中にいる仲間たちはそれぞれ役割がちがう!

  • フィールド:ただの情報置き場(名前などを保存)
  • コンストラクタ:インスタンス化されたときに最初に1回だけ実行される「初期設定メソッド」
  • メソッド:あとから呼び出されて何度でも実行できる処理

たとえば greet() は「こんにちは!」ってしゃべる機能だけど、
コンストラクタは new Hero("ブレイブ") のときに 1回だけ実行される処理だよ。

  • コンストラクタ → newされたときに動く、最初の設定担当
  • メソッド → 呼びたいときに呼んで使う、いろんな機能の担当

メソッドはフィールドの属性(情報)を使って操作ができる。
「🤔フィールドに情報をセットするのがインスタンス化?」 ←じゃない!!

Hero h1 = new Hero("ブレイブ"); で名前の情報が入ったインスタンスができる、けど
Hero h1 = new Hero(); 引数なしでもインスタンス化はできる。(コンストラクタの用意の仕方が変わる)

インスタンス化:基本のかたち

[クラス名] [変数名] = new [クラス名](); // 呼び出し側:mainメソッドの中など

[クラス名]() {} // 呼ばれる側:ここではHeroクラス

「クラス名 変数名 = 」は int num = 5; と似てるよね?

  • int 型の変数名 num に 5 を代入と同じノリで、
  • クラス型の変数名 h1 に new Hero(); を入れる。🤔new・・
    🧙‍♀️あ、new は魂入れてます。
    💫Hero h1 = new Hero();
  • new:生み出すよ!
    • ()が空 → 「デフォルトの魂セット」= 素体
    • ("ブレイブ")引数あり = 遺伝子操作つき召喚

🤔{ 話半分で聞いとけ?本気にしてはダメだ。

インスタンス化はオブジェクトごとに1回だけ

Heroクラスに対して

Hero.java
public class Hero {
    // クラスのメンバーがいる(フィールド)
    String name;
    
    // コンストラクタで名前を初期化
    public Hero(String name) {
        this.name = name;
    }
	
    // 初期化されたnameを使って挨拶する
    public void greet() {
        System.out.println("こんにちは、僕は" + name + "!");
    }
}

インスタンス化を3回に増やしても、Heroクラスの記述は変えなくていい!

Main.java
public class Main {
    public static void main(String[] args) {
	    
        Hero h1 = new Hero("ブレイブ");    // インスタンス化①
        Hero h2 = new Hero("ビクトール");  // インスタンス化②
        Hero h3 = new Hero("マルス");     // インスタンス化③
        h1.greet(); 
        h2.greet(); 
        h3.greet(); 
    }
}

---------------------------------------------------------------------

// Heroクラスのコンストラクタでh1,h2,h3のインスタンス化はできる

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

オブジェクトの属性を増やすときはHeroクラスのフィールドを増やす。

Hero.java
public class Hero {
    // オブジェクトに名前以外の power や speed を持たせる。
    String name;
    int power;
    int speed;
    
    // コンストラクタで名前を初期化
    public Hero(String name) {
        this.name = name;
    }
    // セッターで初期値をセット
    public void set() {
        this.power = 100;
        this.speed = 50;
    }
    
    // 初期化されたnameを使って挨拶する
    public void greet() {
        System.out.println("こんにちは、僕は" + name + "!");
    }
}

セッターへの指示を書く。

Main.java
public class Main {
    public static void main(String[] args) {
	    
        Hero h1 = new Hero("ブレイブ"); // ここでインスタンス化
        h1.set(); // ← powerやspeedに初期値が入る
    }
}

フィールドに情報を入れるのはコンストラクタじゃなくてもいい。
インスタンス化とコンストラクタは1回だけ!
フィールドにセットするのは何回でも!

h1 :name  ブレイブ
   :power 100
   :speed 50   
   
h1オブジェクトにフィールドの情報が紐づいている!   
でも、セットだけしても
h1.greet(); や System.out.println(h1.power) などで出力しないとオブジェクトの状態は分からない!

メモリにいる!コードでは見えないオブジェクト

たとえば、このコードを実行すると、(Mainクラスが実行指示書)

Main.java
public class Main {
    public static void main(String[] args) {
	    
        // newする!
        Hero h1 = new Hero("ブレイブ");    // h1オブジェクト
        Hero h2 = new Hero("ビクトール");  // h2オブジェクト
        Hero h3 = new Hero("マルス");     // h3オブジェクト
	    
        // Heroクラスのset()メソッドを呼び出して、フィールドに値を入れる!
        h1.set();
        h2.set();
        h3.set();
    }
}

(Heroクラスが設計書)

Hero.java
public class Hero {
    // オブジェクトに名前以外の power や speed を持たせる。
    String name; // new → コンストラクタでthis.nameしたら名前が入る
    int power; // h1.set(); → public void set()でthisされたらここに100が入る
    int speed; // h1.set(); → public void set()でthisされたらここに50が入る
    
    // コンストラクタで名前を初期化
    // Mainクラスのnewがここにくるよ💡
    public Hero(String name) {
        this.name = name;
    }
    // セッターで初期値をセット
    public void set() {
    	this.power = 100;
    	this.speed = 50;
    }
}

3つのオブジェクトができている。

h1 :name  ブレイブ   h2 :name  ビクトール   h3 :name  マルス
   :power 100          :power 100            :power 100
   :speed 50           :speed 50             :speed 50
  • System.out.println(); でコンソール出力して確かめることもできる。
  • System.out.println に h1.name(オブジェクトh1の名前)などの指定をして出力。
  • System.out.println(h1); にすると、Hero@6d06d69c みたいな数字が出る!ここがオブジェクトがいる場所!

オブジェクトはメモリの中にいる
「Hero h1 = 」のHeroクラス型の変数名h1というメモリの場所をとって【情報を持った箱(オブジェクト)】が配置されてる。
h1オブジェクトの箱に
・name
・power
・speed
が入っている!

💡new された瞬間に、そのオブジェクトの情報は「メモリ」に格納されてる!

Hero h1 = new Hero("ブレイブ"); // この1文で👇

・JVM(Javaの実行エンジン)が「Hero型の領域」をヒープ領域に確保!
・そこに「name = ブレイブ」という値を保存する!
h1 という変数には「その場所(アドレス)を指し示す矢印」が入ってる!

// 確認したいときのコード 
System.out.println(h1.name); // → ブレイブ

複数のオブジェクトが同じコードで動くとき

h1, h2, h3 とオブジェクトが複数あっても「操作される側」のコードは同じ!

Hero.java
public class Hero {
	
    String name;
    int power;
    int speed;
    
    // コンストラクタで名前を初期化
    public Hero(String name) {
        this.name = name;
    }
    // セッターで初期値をセット
    public void setPower(int power) {
    	this.power = power;
    }
	
    // 初期化されたnameを使って挨拶する
    public void greet() {
        System.out.println("こんにちは、僕は" + name + "! 攻撃力は" + power + "あるよ!");
    }
}

「操作する側」でどのオブジェクトに何をさせるかを設定する!

Main.java
public class Main {
    public static void main(String[] args) {
	    
        Hero h1 = new Hero("ブレイブ");    // h1オブジェクト
        Hero h2 = new Hero("ビクトール");  // h2オブジェクト
        Hero h3 = new Hero("マルス");     // h3オブジェクト
	    
        h1.setPower(100);
        h2.setPower(200);
		
        h1.greet(); // → こんにちは、僕はブレイブ! 攻撃力は100あるよ!
        h2.greet(); // → こんにちは、僕はビクトール! 攻撃力は200あるよ!
        // h3 は名前がマルスでパワーは初期値のまま
        // speed はセットされてないから出力すると 0 : int 型の初期値になる
        // 💡フィールドに型を設定して宣言すると初期値が入るよ
    }
}

クラスのコードは1つでも、mainで「誰に命令するか」で世界が変わる!!
・h1 は h1 のフィールドを持ってるオブジェクト
・h2 は h2 のフィールドを持ってるオブジェクト

h1.greet(); // したときの動き👇

Heroクラスのメソッドにアクセス

Hero.java
public class Hero {
    // メソッドにアクセスするから今は無視
    String name;
    int power;
    int speed;
    
    // 指定されたメソッドにアクセスするから今は無視
    public Hero(String name) {
        this.name = name;
    }
    // 指定されたメソッドにアクセスするから今は無視
    public void setPower(int power) {
    	this.power = power;
    }
	
    // 💡h1のオブジェクトがこのメソッドを使う
    public void greet() {
        System.out.println("こんにちは、僕は" + name + "! 攻撃力は" + power + "あるよ!");
    }
}

✅ Javaの「フィールド」には個人(オブジェクトごと)の世界、個性・状態が入ってる。
インスタンス化したときに決めた変数を起点にそのフィールドをまとめて持ってる箱を「オブジェクト」と呼んでいるイメージ。
💡インスタンス化して「オブジェクト」を作る。
→そこに、いろんなフィールドをセットしたり、もとのフィールド情報を変更したりできる。

フィールドにいる仲間たち

🌙スタティックさん
  みんな、楽しそうだなあ・・
🌱インスタンス君
  スタティックさん!なんでそんな離れたとこにいるの?
🌙スタティックさん
  クラスに変化があったら記録しなきゃだから、全体が見える位置にいようと思ってね
🌱インスタンス君
  さすが委員長!大変だなあ
🌙スタティックさん
  ずっとこのクラスにいるからね

Hero.java
public class Hero {
    // フィールド
    String name;
    int power;
    int speed;
    
    // 🌙スタティックさん(クラス変数)!全Heroで共有
    // スタティックさんもフィールドだけど、インスタンス変数とは関係のない存在!
    static int heroCount;
    
    // コンストラクタ:インスタンス化のたびにカウントアップ!
    public Hero(String name) {
        this.name = name; // インスタンス変数に名前をセットする。
        heroCount++;  // 🌙新しいHeroが生まれるたびに増える!スタティック変数への操作。
    }
    
    public void set() {
        this.power = 100;
        this.speed = 50;
    }
    
    public void greet() {
        System.out.println("こんにちは、僕は" + name + "! 攻撃力は" + power + "速さは" + speed + "あるよ!");
    }
    
    // 📢 クラスメンバであるheroCountの表示
    public static void showHeroCount() {
        System.out.println("今までに生まれたHeroの数:" + heroCount);
    }
}
Main.java
public class Main {
    public static void main(String[] args) {
    
        Hero h1 = new Hero("ブレイブ");
        Hero h2 = new Hero("ビクトール");
        Hero h3 = new Hero("マルス");
        
        // メソッドの操作に初期値が入ってるからここでは引数なし
        h1.set();
        h2.set();
        h3.set();
        
        h1.greet();
        h2.greet();
        h3.greet();
        
        // 🌙スタティックさんからのお知らせ
        Hero.showHeroCount(); // → 今までに生まれたHeroの数:3
    }
}

スタティック変数は「クラス変数」と呼ばれる クラスにくっついてる変数!
💡インスタンス化されなくても使える
インスタンス変数は「実体」として数が増えるけど、
スタティック変数は「記憶」が増えるイメージ。個別保存じゃなくて上書き保存されていく。
クラス全体で共有されるからカウントなどが得意。

  • インスタンス変数が「個別の記録ノート」 なら、
  • スタティック変数は「教室のホワイトボード」!

✨static が付くと、クラス全体で1つだけ共有される クラス変数!
✨メソッドも同様に、staticがあれば「クラスメソッド」!

スタティックさんはmainメソッドを支える重要な役目も持ってて魅力的な存在だけど、
ここでは、フィールドの場所には

・このオブジェクト用のフィールド
・あのオブジェクト用のフィールド
・また別のスタティック変数!

など、いろんなフィールドが並ぶことがあるよ!ってところがポイント!

抑えておきたい、ちょっとしたポイント

メンバ変数やクラスを考えるときに分かっておきたいこと。

クラスのフィールドとして宣言すると

    String name;      //初期値でnullが入る
    int power;       //初期値で0が入る
    static int heroCount; //初期値で0が入る

宣言した型に合った初期値が自動で入ってる。

ローカル変数(メソッドの中で使う変数)で宣言だけしても

public void test() {
    int x;         // ← 初期化してない
    System.out.println(x); // ← コンパイルエラーになる!!
}

ローカル変数は、明示的に初期値を入れないとダメ!勝手に0は入らない。

メンバ変数もイコールで初期値を設定できるけど

public class Hero {
    String name = "ななし";
    int power = 10;
}

new してないと、初期値どころかそもそも存在していない状態!
クラスが「設計図」、new でやっと「実体」が生まれる。ってことを思い出してね🌱
※ただし、 スタティック変数(static) だけは例外で、 newしなくても使える特別な子 だよ!

最後に:ここまで読んでいただき、ありがとうございます。

オブジェクトのイメージ理解の足しになればいいなと思って書きました。

クラスやメソッドなど、Javaのいろんな部品が関わってくる中で、
「インスタンス化」ひとつとっても、場面によって感じ方が変わったり、
「あれ?さっき分かったと思ったのに…」ってなること、たくさんありました。

私自身、書きながら「まだ全然分かってないかも…」って思うことも多くて、
でも、それでも少しずつ「なるほど!」が増えてきた気がしています。

もしこの文章が、同じように悩んでる誰かの「なるほど!」のきっかけになったら、とてもうれしいです🌱

ここまで読んでくださって、本当にありがとうございました。

GitHubで編集を提案

Discussion