🗂

【Java入門】変数の型とインスタンスの実体の違い

に公開

型とインスタンスを「容器と容器」として理解する

🔰 はじめに

Javaの学習を進める中で、多くの人が混乱するポイントの一つに、
「変数の型(クラス)と、newで生成されたインスタンスの実体の違い」 があります。

この違いは、Javaの継承やオーバーライドといったオブジェクト指向の基本に関わる、とても重要な概念です。

この章では、「クラスはすべて容器である」という考え方を軸にして、
「型とインスタンスの違い」 を視覚的・構造的に理解できるよう解説していきます。


🎁 1. 「容器と容器」でとらえる型と実体

A obj = new B();

このコードが意味しているのは:

要素 たとえ 説明
A(型) Aという仕様の容器 コンパイル時に見られる容器(表札)
new B() Bという構造の容器 実行時に使われる実体の容器

Javaでは、変数の型と実際に生成されたインスタンスは別の容器として扱われます。
このとき、型は“見た目の仕様”、インスタンスは“中身の真の構造” と考えると理解が進みます。


🧠 2. コンパイル時と実行時の役割の違い

Javaのメソッド呼び出しは、以下のようにフェーズによって判断基準が異なります:

フェーズ 見ているもの どう判断するか
コンパイル時 変数の型(容器A) 「その容器にそのメソッドがあるか?」で判断
実行時 インスタンスの実体(B) オーバーライドされていればBの中のメソッドが実行される

💥 3. 同名メソッドが両方の容器にある場合

class A {
    void greet() {
        System.out.println("こんにちは、Aです");
    }
}

class B extends A {
    @Override
    void greet() {
        System.out.println("こんにちは、Bです");
    }
}

A obj = new B();
obj.greet();  // → 出力:こんにちは、Bです
  • obj はA型 → コンパイラは「A容器に greet() がある」のでOK
  • 実体はB → 実行時には、B容器にある greet() が呼び出される

👉 これが 動的バインディング(実行時に実体に応じてメソッドを決定する仕組み) です。


🚫 4. Bにしかないメソッドを呼ぼうとすると?

class B extends A {
    void onlyInB() {
        System.out.println("Bだけのメソッド");
    }
}

A obj = new B();
obj.onlyInB(); // ❌ コンパイルエラー

理由:

  • 変数 obj の型は A → A容器に onlyInB() は無い
  • コンパイル時点で「そんなメソッドは知らん」とエラーになる

たとえ中身がBでも、
“見えている容器がAなら、Aにあるものしか使えない” のがJavaのルールです。


🧪 5. 容器のイメージで整理すると…

  • A型:Aという仕様の容器(例:機能が3つの箱)
  • B型:Aを拡張したB容器(例:機能が5つの箱)
A obj = new B();
  • obj に貼られているラベルは「A」
  • 中身は「B」だとしても、見た目がAなのでAの中身しか見えない
  • オーバーライドされたメソッドだけは、実行時に「中身の容器B」 が呼ばれる

📌 6. メソッド内で使われる変数はどの容器を見るか?

class A {
    int value = 10;
    void show() {
        System.out.println("Aのvalue: " + value);
    }
}

class B extends A {
    int value = 20;
    @Override
    void show() {
        System.out.println("Bのvalue: " + value);         // → 20
        System.out.println("Aのvalue: " + super.value);   // → 10
    }
}
  • メソッド show()B容器 に定義されているので、
    そこでは Bの value が参照される(= シャドウイング(隠蔽))。

✅ 7. まとめ:容器と容器を明確に分けて考えよう!

用語 意味
変数の型(クラス) 表札としての容器。コンパイル時に何が使えるかを決める
インスタンス(実体) 中身としての容器。実行時に実際に使われる処理を持つ
静的バインディング コンパイル時に「型の容器」からメソッドや変数を探す
動的バインディング 実行時に「実体の容器」からオーバーライドされたメソッドを選んで実行

このように、「見た目の容器(型)」と「中身の容器(インスタンス)」 を分けて考えることで、
Javaの振る舞いがより明確に理解できる ようになります。


Discussion