【Java】Javaのstaticの意味とは?インスタンスとの違いを初心者向けに解説

Java

こんにちは、かつコーチです。

public static void mainstaticって何のためについているんだろう」と疑問に思ったことはありませんか。
static(クラスに1つだけ存在する、インスタンスに依存しないメンバーを表すキーワード)は、Java学習の初期でつまずきやすいポイントの1つです。
この記事では、staticとインスタンスの違いを、具体例を通して整理します。

staticとは

クラスに属するかインスタンスに属するか

Javaのクラスには、大きく分けて2種類のメンバー(変数・メソッド)があります。

  • インスタンスメンバーnewでオブジェクト(インスタンス)を作るたびに、それぞれ別々に持つデータ・処理
  • staticメンバー:クラス自体に1つだけ存在し、すべてのインスタンスで共有されるデータ・処理
public class Counter {
    static int totalCount = 0; // クラスに1つだけ(staticメンバー)
    int myCount = 0;           // インスタンスごとに別々(インスタンスメンバー)

    public void increment() {
        totalCount++;
        myCount++;
    }
}

totalCountCounterクラス全体で1つしか存在しませんが、myCountnew Counter()するたびに新しく作られます。

なぜstaticが必要なのか

「インスタンスを作らなくても呼び出せる」「全インスタンスで値を共有したい」という場面で、staticが役立ちます。

たとえばmainメソッドがstaticなのは、プログラム起動時にはまだ1つもインスタンスが作られていないためです。
インスタンスがない状態でも呼び出せるように、mainstaticである必要があります。

基本の書き方・実装手順

手順1:staticなし(インスタンスメンバー)の場合

public class Dog {
    String name;

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

    public void bark() {
        System.out.println(name + ":ワン!");
    }
}
Dog dog1 = new Dog("ポチ");
Dog dog2 = new Dog("タロウ");
dog1.bark(); // ポチ:ワン!
dog2.bark(); // タロウ:ワン!

nameはインスタンスごとに独立しているため、dog1dog2で別々の値を持てます。

手順2:staticあり(全インスタンス共有)の場合

public class Dog {
    static int dogCount = 0; // 全インスタンスで共有するカウンター
    String name;

    public Dog(String name) {
        this.name = name;
        dogCount++; // インスタンスが作られるたびに増える
    }
}
Dog dog1 = new Dog("ポチ");
Dog dog2 = new Dog("タロウ");
System.out.println(Dog.dogCount); // 2

dogCountはどのインスタンスからアクセスしても同じ値を参照します。
staticメンバーには、インスタンス変数名.dogCountではなくクラス名.dogCountでアクセスするのが基本ルールです。

手順3:staticメソッドの定義

public class MathUtil {
    public static int square(int n) {
        return n * n;
    }
}
int result = MathUtil.square(5); // インスタンスを作らずに呼び出せる
System.out.println(result); // 25

MathUtil.square(5)のように、インスタンスを作らずクラス名から直接呼び出せるのがstaticメソッドの特徴です。

つまずきやすい設定・注意点

staticメソッドの中からは、インスタンスメンバー(staticでない変数・メソッド)を直接使うことはできません。
これは、staticメソッドが呼ばれる時点で、どのインスタンスの値を使えばいいか特定できないためです。

よくあるつまずきポイント・エラー対処

staticメソッドからインスタンス変数にアクセスしてエラーになる

初心者が実際によくつまずくのが、mainメソッド(static)から、インスタンス変数を直接使おうとするケースです。

❌Before

public class Sample {
    int value = 10; // インスタンス変数

    public static void main(String[] args) {
        System.out.println(value); // コンパイルエラー
    }
}

このコードをコンパイルすると、次のエラーが出ます。

error: non-static variable value cannot be referenced from a static context

私も最初にこのエラーを見たとき、「なぜ同じクラスの中なのにアクセスできないのか」と混乱しました。
mainはstaticなので、インスタンスが1つも存在しない状態でも実行されます。
インスタンスが存在しないのに、インスタンスごとに異なるvalueを参照することはできない、というのがエラーの理由です。

✅After

インスタンス変数を使いたい場合は、mainの中で明示的にインスタンスを作成してからアクセスします。

public class Sample {
    int value = 10;

    public static void main(String[] args) {
        Sample sample = new Sample(); // インスタンスを作る
        System.out.println(sample.value); // 10
    }
}

staticフィールドを意図せず共有してしまう

staticフィールドは全インスタンスで共有されるため、「インスタンスごとに別々の値を持たせたかったのに、staticを付けてしまい値が混ざる」というミスも起こりがちです。

public class ShoppingCart {
    static int itemCount = 0; // 本来はインスタンスごとに持たせたい値

    public void addItem() {
        itemCount++;
    }
}
ShoppingCart cartA = new ShoppingCart();
ShoppingCart cartB = new ShoppingCart();
cartA.addItem();
cartB.addItem();
System.out.println(cartA.itemCount); // 2(cartAだけの数のつもりが混ざっている)

「このデータはインスタンスごとに独立させたいか、全体で共有したいか」を意識してstaticの有無を判断することが重要です。

応用・一歩先の使い方

static importとユーティリティクラス

MathUtilのように、インスタンス化せず使うメソッドだけを集めたクラスはユーティリティクラスと呼ばれ、実務でも頻繁に登場します。
Math.max()Collections.sort()など、Java標準ライブラリのユーティリティ系クラスの多くもこの設計です。

また、import static java.lang.Math.max;のように書くstatic importを使うと、Math.max(a, b)max(a, b)のようにクラス名を省略して呼び出すこともできます。

まとめ

この記事のポイント

  • staticはクラスに1つだけ存在し、全インスタンスで共有されるメンバーを表す
  • インスタンスメンバーはnewするたびに別々に作られる
  • staticメソッドの中からインスタンスメンバーへ直接アクセスするとコンパイルエラーになる
  • 「インスタンスごとに独立させたいか、全体で共有したいか」を基準にstaticの有無を判断する

次に読むべき記事

  • 変更できない値を扱うfinalキーワードの使い方は、次の記事で解説します
  • クラスとオブジェクトの基本をまだ確認していない方は、次章の記事もあわせてご覧ください

タグ: Java, 初心者向け, 基本文法

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