PR

Java:ローカル変数/インスタンス変数/クラス変数の違いと使い分けを1分で整理

Java

Javaのプログラムを組むうえで、最初にぶち当たる壁となりがちなのが「変数の種類と使い分け」です。

Javaでは大きく分けて、ローカル変数インスタンス変数クラス変数の3つが存在します。どうして複数の種類があるのか、その根本的な理由を理解すると、使い分けが自然に身につきやすくなります。ここでは初心者の方にもイメージしやすいように、なるべく平易な言葉で解説していきます。

スポンサーリンク

変数とは「データを一時的にしまっておく箱」

そもそも「変数」とは何でしょうか?
プログラムでは、何かしらデータ(数値、文字、文字列、オブジェクトなど)を扱うときに、そのデータを一時的にメモリに保存し、取り出したり書き換えたりします。この「データを置いておく場所」のことを変数と呼びます。

しかしJavaでは、この「変数をどこに置くか」がいくつかパターンあります。
それが、ローカル変数インスタンス変数クラス変数です。

Javaのローカル変数

ローカル変数の定義とイメージ

ローカル変数とは、メソッドの中で宣言し、そのメソッド内でだけ使える変数のことです。

  • 例:public void doSomething() { int x = 10; ... }

このxはメソッドが呼び出されて処理が走り始めるとメモリ上に生まれ、メソッドの処理が終わると一緒に消えていきます。(参考 Javaのメソッドとは?基本を1から

なぜメソッド内だけなのか?

プログラムはメソッドごとに処理をまとめて呼び出します。呼ばれたときに必要な情報だけ一時的に用意して、終わったら捨てるほうが、メモリを効率的に使えます。そこで、メソッド内だけで使い終わるデータは「局所的(ローカル)」に保持するという仕組みになっているわけです。

ローカル変数の初期化の重要性

Javaでは、ローカル変数は自動で初期化されません。これはメモリの仕組み上、明確に値が入るとわからない変数を使うとバグになりやすいため、あえてコンパイラレベルで強制しているのです。

void sampleMethod() {
    int count; // 初期化しないまま...
    // System.out.println(count); // エラー: 初期化されていない変数は使えない
}

明示的に初期値を指定しないと「値が不定」という状態を避けられないので、コンパイルエラーになります。これは「安全対策」だと捉えてください。

varが使える理由

Java 10以降、ローカル変数に対してvarでの型推論(参考 「var」宣言の基本)が使えるようになりました。これは宣言と同時に代入することで、「入ってくるデータ型がその場で決まっている」からこそ可能になった仕組みです。

void example() {
    var num = 10; // ここでは自動的にint型と推論される
}

一方で、インスタンス変数やクラス変数ではvarが使えません。それは、クラスが読み込まれる段階で型推論する情報がないからと理解すると自然です。

インスタンス変数

インスタンス変数の定義とイメージ

次はインスタンス変数です。クラスの中でメソッドの外に宣言した変数が、インスタンス化(newを使ってオブジェクトを生成)されたときに割り当てられます。

public class Person {
    int age;       // インスタンス変数
    String name;   // インスタンス変数

    public Person() {
        age = 20;
        name = "Unknown";
    }
}

このagenameは、それぞれのPersonオブジェクトが生まれたときに領域が確保されます。たとえば、Person p1 = new Person();Person p2 = new Person();を実行すると、p1p2それぞれが自分専用のagenameを持つイメージです。

なぜ自動的にデフォルト値が設定されるのか

インスタンス変数は自動的に0やnullなどのデフォルト値が設定されます。これはヒープ領域(オブジェクトを管理するためのメモリ領域)を確保するときにJVM(Java Virtual Machine)が「ゴミが残らないように必ず初期状態を揃える」仕組みを用意しているためです。

逆に、ローカル変数のように局所的に使われるものは「明示的に初期化しないなら使わせない」という安全策が働きます。これが変数の種類による「自動初期化」の差につながっています。

デフォルト値の設定→ある変数が生成されたタイミングで、自動的に0やfalsenullなどの値が割り当てられることを指します。具体的には下記のような初期値が入ります:

  • 整数系(int, long, short, byte):0
  • 浮動小数点系(float, double):0.0
  • booleanfalse
  • 参照型(String, その他のクラス型):null

ポイント デフォルト値が設定される理由

1:ヒープ領域の初期化による恩恵

Javaのインスタンス変数やクラス変数は、ヒープ領域やメタスペース(クラスの情報を管理する領域)などで管理されます。ヒープ領域に確保したメモリは、「予期せぬゴミデータが残らないように、あらかじめ安全な値に初期化する」という仕組みになっています。

  • インスタンス変数newキーワードでオブジェクトを生成した際、ヒープ領域に確保された変数は自動的にデフォルト値がセットされます。
  • クラス変数(static変数):クラスをロードするときに同様の仕組みでメモリが初期化されます。

2:バグの軽減と安全性の向上

もしヒープ領域にランダムなゴミデータが残った状態でオブジェクトを生成してしまうと、プログラムは意図しない動きをする恐れがあります。C/C++など一部の言語では、自分で明示的に初期化しないとゴミデータを参照してしまうケースがあるため、バグが起こりやすいという問題点がありました。

Javaでは、こうした事故を減らすため、インスタンス変数やクラス変数には必ず安全なデフォルト値を設定する設計になっているのです。結果として「どんな変数でも、一貫した初期状態が保証される」メリットがあります。

3:ローカル変数は自動初期化されない

一方、メソッド内で使うローカル変数はデフォルト値がつきません。これは逆に「初期化のし忘れによるバグ」をコンパイラで検出する」ために、あえて自動初期化を行わない仕様です。ローカル変数は一時的に使い捨てる性質のため、明示的に初期化をしなければコンパイルエラーにしてしまうことで、プログラマのミスを強制的に防いでいます。

クラス変数(static変数)

クラス変数の定義とイメージ

staticを付けて宣言した変数は、クラス変数(static変数)と呼ばれます。これはインスタンスを作らなくても、クラスに対して1つだけ存在する変数です。

public class Counter {
    static int totalCount = 0;

    public Counter() {
        totalCount++;
    }
}

上記コードだと、new Counter()するたびにtotalCountがインクリメントされます。インスタンスの数とは関係なく、クラスとしてひとつだけ存在するグローバルな変数というイメージです。

クラス変数もデフォルト値が設定される

クラス変数もヒープではなくメソッド領域(またはメタスペース)と呼ばれる領域で管理されます。このときも、自動で0やnullといったデフォルト値が割り当てられます。クラスがロードされるタイミングで「このクラス変数には必ず何らかの初期値をセットしておこう」という仕組みが働くためです。

使い分けのポイント

変数の種類と動作原理を理解すると、「この場面ではどの変数を使うべきか?」が自然とイメージしやすくなります。

  1. メソッドの内部だけで値を扱いたいローカル変数
    • 例:計算途中の一時的な値、メソッドのパラメータやループカウンタなど。
    • 使用後は破棄されるので、メモリ効率が良くなる。
  2. オブジェクトごとに異なる値を持たせたいインスタンス変数
    • 例:Personごとの年齢や名前、Carごとの車種。
    • それぞれのインスタンスにひも付いてデータを保持する。
  3. クラス全体で共有したい情報を持たせたいクラス変数(static)
    • 例:生成したオブジェクトの総数、アプリ全体で使う定数値など。
    • インスタンスに関係なく、クラスに1つだけ存在するデータ。

このように役割がはっきりしているので、「どの範囲で値を使う必要があるか?」が最優先の判断基準となります。

タイトルとURLをコピーしました