🌟

Javaクラスの世界で働く小人たち ~変数とメソッドのおしごと~

に公開

はじめに:

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

登場人物と設定

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

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

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

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

Aクラス (LessonA.java)

🌱インスタンス君

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

🌙スタティックさん

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

😎ゲッター君

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

⚙️セッターさん

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

🌟voidちゃん

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

🎓計算くん:メソッド階級

  • ローカル変数という特別な小人と仲良し。
  • ローカル変数小人の存在は世に出したら混乱するって思って秘密にしている。(”秘密にしている”は今回の物語の都合上の設定です。)

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

コメントアウトさん

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

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

働きものの小人さん 【メソッドの小部屋】

【計算くんの疑問】
”計算くん”は 自分専用の部屋 を持っている。
メソッド階級なら持っているものだが、他のメソッド部屋の中のことは知らなかった。
「いつも仕事を手伝ってくれる小人さんは何者なんだ?」
神のお告げ "java - Main" で覚醒状態で働くときは夢中になって全てを受け入れてしまうけど、
冷静に振り返ってみたとき・・さっき、小人いた?
インスタンス君の小さい感じの、なにか、そんな存在がいたんだ。
仕事部屋に届いた引数を開封したあと計算を手伝ってくれる存在、そんな存在がいつもいる、でも今はいない。
メソッド階級仲間のアブストラクトさんは「仕事部屋にはいつも何もいないよ?」といった。
抽象的すぎて、言ってることがよく分からないアブストラクトさん
唯一はっきりと主張した言葉だった。

public int add(int a, int b) {
	return a + b;  // ローカル変数:a と、ローカル変数:b の登場
}

💡引数やローカル変数はメソッド内でのみ存在する。
💡ローカル変数はメソッドが終了したらいなくなる。
   【比べると→】インスタンス変数は宣言されたらずっといる。

※実際には、ローカル変数もメソッドの中でふつうに使われているし、ちゃんとコードの中で見えて秘密の存在ではないですが、
→ ローカル変数は「そのメソッドの中だけ」に現れて、「外には持ち出せない」
→ インスタンス変数とは生きてる時間や場所がちがう!
という点があるので、「実体があるけどあっという間に消える不思議な存在」として “小人”にたとえた ストーリーになっています。

【小人の残したもの】
計算くんは、名前の通りに計算が得意で論理的に考えることも得意だ。
だから説明できないこと、あり得ないことも、なんとなくもういいと割り切ることはできなかった。
限界まで調べて考えるんだ!そういえば、
mainさんはリターンを受けっとているはず・・!

public int add(int a, int b) {
    // ローカル変数: a と b は一時的な小人のような存在
    int result = a + b;  // ここで結果を残す
    return result; // returnで足跡が残る!
}

💡return は「returnの後に続くもの」を呼び出し元に返してメソッドを終了する。

public int add(int a, int b) {
    int result = a + b; 
    return result; // result を main に返してメソッドを終了
    System.out.println(result) // ここは実行されない
}

【mainメソッドさんが教えてくれたこと】
mainさんはいつも飴をくれる。たまにチョコレートや小さいケーキ菓子のときもある。
話してみると、mainさんもローカル変数の小人を知っていた。
隙あらば飴を渡そうとしているが”神のお告げ実行中”は難しい!と、残念そうだった。
mainさんは当たり前のように、神様がいるんだから小人も精霊もいるわよ~🤗と、
エラーで会えるレア精霊の話をしてくれた。
お菓子の受け渡しに成功すると要求してくるようになるらしい、でも長居はしてくれないそうだ、仕事で来てるんだもんな。

public class Main {
    public static void main(String[] args) { // ← Mainクラスのmainさん:メソッド
        // mainさんの小人 sum が活躍
        int sum = add(5, 7);  // addメソッドを呼び出し、戻り値を sum に格納
        System.out.println("結果: " + sum);  // 返ってきた結果を出力
    }
}

💡int sum = add(5, 7);
答えの受け皿 int sum と メソッド呼び出し add(5, 7) を1文で表記。

NullPointerException 
// mainさんが餌付けに成功した子
🧘‍♂️ Nullの精霊: 「私はヌル参照。あんたらのコードが私を避けられない限り、どこにでも出てくるぞ。」
アブストラクト(abstract)さんについて

アブストラクト:キーワードは”抽象”!アブストラクトにはクラスとメソッドがある。
抽象クラス ( abstract class )

  • 他のクラスに継承されて、共通の機能やメソッドを提供するためのクラス。
  • インスタンス化できないクラス。
  • 少なくとも1つ以上の抽象メソッドを含んでいることが一般的である(絶対ではない)。
    抽象メソッド ( abstract method )
  • メソッドの定義はあるけれど、その実装がないメソッド。
  • 実装はサブクラスで提供しなければならないことを示す。
  • 抽象メソッドを含むクラスは必ず抽象クラスでなければならない。
abstract class Animal {
    // 抽象メソッド(実装なし)← サブクラスで実装する。
    abstract void sound();
    // 普通のメソッド(実装あり)
    void eat() {
        System.out.println("Animal is eating");
    }
}
// サブクラス "extends Animal" class Animalを継承
class Dog extends Animal {
    // 抽象メソッド sound() を実装
    void sound() {
        System.out.println("Woof");
    }
}
  • abstract:「中身が決まってない」将来何をするかまだ分からない✨
  • 「実装はサブクラス任せ」具体的なことは配属ガチャで決まる⚡

出入り口の秘密【引数と戻り値、そしてメソッド間移動】

【フィールドのルール】
フィールドの場所にいるインスタンスたちは、各々自分のメンバー変数(属性)を持っているが、それに手を加えるのはメソッドの役目。
メソッド階級の人たちは、自分の道具(メソッド)を自分の管理下で使い、インスタンスのデータ(フィールド)は適切に管理していく。
フィールドにアクセスする人たちは、それぞれのメンバーのデータを操作することができるが、その方法はあくまで決められた手順に従うこと。これが、プライベートパブリックの修飾子で決まる「アクセス権」に相当する。

public class Calculator {
    private int num1;  // フィールドに保管されている変数
    private int num2;  // インスタンス君のメンバー
    
    public Calculator(int num1, int num2) {  // コンストラクタ(インスタンス化の際に呼ばれる)
        this.num1 = num1; // this.num1(このクラスのnum1)に引数(他のクラスから来た値)で初期化
        this.num2 = num2;
    }
    
    // メソッド階級:データを使って計算
    public int add() {
        // Calculatorクラスの中だからプライベートフィールドにアクセスできる!
        return this.num1 + this.num2;  // フィールドにアクセスして結果を計算
    }
}
public class LessonA { // あれ?コンストラクタいない?👉デフォルトコンストラクタ
    // メンバ変数
    String name;
    int power;
    //  fightメソッド
    public void fight(int energy, int mental) {
        power = energy + mental;
    }
}

【fightメソッド】

public void fight (修飾子・戻り値・名前) 「玄関の表札みたいなやつ」

  • public 「この家、誰でも訪問OKだよ~🏠」
  • void 「ごめんね、お土産ないんだ・・(返り値なし)」
  • fight 「玄関の表札:fight研究室」

(int energy, int mental) 引数 ( )で受け取る!「ポストに届く✉」

  • 材料2つ
  • (1つ目, 2つ目)

{power = energy + mental;} { }の中で操作!「これが実際の仕事」

  • ポストに届いた材料で作業開始!

💡 POINT 💡送り主(mainさんなど)から「引数」として「ローカル変数」が届く
👉「引数」という枠に材料が届く
👉材料が「ローカル変数」というメソッドの道具に実装される!

コンストラクタとは?
  • インスタンスの初期化のために1度だけ使われる。
  • 書いてないと引数なしのデフォルトコンストラクタが自動で作成されてる。
public class LessonA { // あれ?コンストラクタいない?👉デフォルトコンストラクタ
    // メンバ変数
    String name;
    int power;
    // メソッド
    public void fight(int energy, int mental) { // 引数を受け取る
        power = energy + mental;
    }
}
---------------------------------------------------------------------------------
    // Javaが勝手に引数なしのコンストラクタを用意してる
    public LessonA() { }
---------------------------------------------------------------------------------
    public class LessonA {
    // メンバ変数
    String name; // ← null(参照型)デフォルトコンストラクタで初期化
    int power;   // ← 0(int型)デフォルトコンストラクタで初期化
    // メソッド
    public void fight(int energy, int mental) { // 引数を受け取る
        power = energy + mental;  // ← powerは最初0だったけど、ここで上書きされる!
    }
}

💡引数ありのコンストラクタを明示的に書いたらデフォルトコンストラクタは用意されない。

public class Player {
    String name;
    int hp;
    // 明示的なコンストラクタ
    public Player(String name) {
        this.name = name;  // name は値を受け取ってセット
        this.hp = 100;  // hp は必ずHP100でスタート!
    }
}
  • コンストラクタはクラス名と一致
    • public class Playerのコンストラクタ → public Player( ) { }
  • コンストラクタじゃないメソッドだとクラス名とは違う名前
    • public class Playerのメソッド → public increaseHp( ) { }
// まとめて初期化
public class LessonA { 
    // メンバ変数
    String name;
    int power;
	
    LessonA(){} // 引数なしコンストラクタはフィールドの数に関係なくこれ
	
    // メソッド
    public void fight(int energy, int mental) { // 引数を受け取る
        power = energy + mental;
    }
}
------------------------------------------------------------------------------
// 引数なしのインスタンス化
public class Main {
    public static void main(String[] args) { 
	    
        LessonA knight = new LessonA();
    }
}
------------------------------------------------------------------------------
// 引数なしのコンストラクタでセット
public class LessonA {
    String name;
    int power;

    // 引数なしコンストラクタだけど、中で初期値をセットしてる!
    LessonA() {
        this.name = "無名の戦士";
        this.power = 100;
        // インスタンスが作られた目印を表示することもできる!
        System.out.println("LessonAの新しい戦士が誕生した!");
    }
}
public class LessonA { 
    // メンバ変数
    String name;
	int power;
	
    LessonA(String name, int power){ // 明示的なコンストラクタ
    	this.name = name;
    	this.power = power;
    } 
	
    // メソッド
    public void fight(int energy, int mental) { // 引数を受け取る
        power = energy + mental;
    }
}
------------------------------------------------------------------------------
// 引数ありのインスタンス化
public class Main {
    public static void main(String[] args) { 
        
        LessonA knight = new LessonA("Crow", 300); // ← 文字列は "" で囲む!
    }
}
  • 引数ありコンストラクタ、引数なしコンストラクタ、両方必要な場合は両方明示的に書く!

クラスメンバたち

public class LessonA {

    // クラス変数(static)← クラス全体で共有される
    static int classCount = 0;

    // インスタンス変数(フィールド)← インスタンスごとに値を持つ
    String name;

    // コンストラクタ:インスタンス生成時に呼ばれる
    public LessonA(String name) {
        this.name = name;       // 引数の値をインスタンス変数に代入
        classCount++;           // 全体の数を1増やす
    }

    // メソッド:ローカル変数を使う例
    public void greet() {
        String greeting = "こんにちは、" + name + "さん!"; // ← ローカル変数greeting
        System.out.println(greeting);
    }

    // クラス変数の表示
    public static void showClassCount() {
        System.out.println("今までに作られたインスタンスの数: " + classCount);
    }
}

↓ 呼び出し側クラス

public class Main {
    public static void main(String[] args) {
        // ここでインスタンス化
        LessonA a = new LessonA("たろう");  
        LessonA b = new LessonA("はなこ");
        
        // ここで呼び出し
        a.greet(); // → こんにちは、たろうさん!
        b.greet(); // → こんにちは、はなこさん!

        LessonA.showClassCount(); // → 今までに作られたインスタンスの数: 2
    }
}
  • LessonAのオブジェクトを作ってgreetメソッドを呼び出し。
  • コンストラクタで初期化"たろう"など値が入る。
  • greetメソッドのローカル変数greetingにメンバ変数を使った文章が代入される。
  • greetメソッドはvoid(呼び出し側に返らない)でその場でSystem.out.printlnして終了する。
  • スタティックのクラス変数は「クラスにくっついてる」変数
    • 【比較】インスタンス変数はオブジェクト単位!
    • クラス変数はクラス単位!
    • クラスで起こったことを記録するのに便利

クラス間のつながり方

なにも気にせずアクセスできる例

LessonA.java
public class LessonA {
    public String name = "たろう";
}
Main.java
public class Main {
    public static void main(String[] args) {
        LessonA a = new LessonA();
        System.out.println(a.name); // → たろう
    }
}
  • フィールドがパブリック(public String name)やパッケージプライベート(String name)ならそのままアクセス。

ゲッターを使う例

LessonA.java
public class LessonA {
    private String name;
    // コンストラクタ
    public LessonA(String name) {
        this.name = name;
    }
    // ゲッターの登場!
    public String getName() { // ← 取り出すためのメソッド!
        return name;
    }
}
Main.java
public class Main {
    public static void main(String[] args) {
        LessonA a = new LessonA("たろう");
        System.out.println(a.getName()); // → たろう
    }
}
  • フィールドがプライベートなときはゲッターなど窓口を通す。

メソッド間移動の例

LessonA.java
public class LessonA {
    public int add(int a, int b) { // ← 引数で届くローカル変数 a, b
        int result = a + b;        // ← メソッド内でだけ生きるローカル変数
        return result;             // ← 呼び出し元に戻す
    }
}
Main.java
public class Main {
    public static void main(String[] args) {
        LessonA tool = new LessonA();
        int total = tool.add(5, 3); // 引数で渡して、戻り値で受け取る
        System.out.println("合計: " + total); // → 合計: 8
    }
}
  • ローカル変数はフィールドに関係なくメソッドの中で動く!
SecretTool.java
public class SecretTool {
    
    public void use() {
        int result = secretAdd(3, 4); // ← 同じクラスの中だから呼べる!
        System.out.println("結果: " + result);
    }

    // パブリック・プライベートを考えるための例
    // 実際に使うのはめんどうかも😅
    public int backstagePass(int a, int b) { // mainが直接呼べないプライベートをmainの代わりに呼び出して返す。
        int answer = secretAdd(a, b); // ← 同じクラスの中だから呼べる!
        return answer;
    }

    private int secretAdd(int a, int b) { // ← プライベートなローカルトンネル
        return a + b;
    }
}
Main.java
public class Main {
    public static void main(String[] args) {
        SecretTool tool = new SecretTool();
        tool.use(); // ← OK!
        int answer = tool.backstagePass(7, 5);
        
        // tool.secretAdd(3, 4); // ← ❌ 外からは呼べない!ドア閉まってる!

        System.out.println("合計: " + answer);
    }
}

インスタンス化とコンストラクタは一緒に覚える!

new クラス名() って書いたとき、
「クラス名() はそのクラスのコンストラクタを呼び出してる」!

Main.java
LessonA knight = new LessonA();
  • LessonA knight:LessonA型の変数 knight を宣言
  • new LessonA():LessonAのインスタンスを生成する(このときコンストラクタが呼ばれる!)
LessonA.java
public class LessonA {
    public LessonA() {
        System.out.println("LessonAのコンストラクタが呼ばれた!");
    }
}

メインクラスでnew LessonA() って書いたときに、このLessonAクラスの「LessonA()」が呼ばれる!!

  • new クラス名() は「インスタンス作る + コンストラクタを呼ぶ」を一気にやってる!
  • クラス名() は、newするときに1回だけ実行される初期設定のレシピ!
  • 書き忘れてると最低限の「デフォルトコンストラクタ」が用意される!😳{忘れものよ!💦

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

Javaの資格勉強中、スタティックの動きに混乱し、メソッドとコンストラクタの違いがわからず、
継承で「もう無理!」と思ったこともありました。

でも、ノリとキャラ設定で覚えたら、案外なんとかなった!

たとえば…

  • 法律や社会ルールabstract(「守れ」って言うけど詳細は各人まかせ)
  • 学校や会社の指導interface(「これこれやりなさい」って複数強制される)
  • 大人になるimplements(色んなインターフェースを実装して生きていく)
  • たまに「こうしなさい」と決め打ちされる規則final(もう上書き不可)
  • 大人になるまで何するか分からないけど、やるしかない抽象メソッドの実装待ち
  • 遺伝や家庭環境親クラス(継承元)

これからも「分かりやすいって、楽しい!」をテーマに、
記事を追記・編集しながら育てていく予定です。どうぞよろしくお願いします。

GitHubで編集を提案

Discussion