staticキーワード:クラスの仲間

docs

引き続き、**「クラス」と「インスタンス(オブジェクト)」**について学んでいきます。

クラスとオブジェクトの概念 – オブジェクト指向の入り口 | ToolDocs

クラスが設計図で、インスタンスがそれに基づいて作られた実体、という話でしたね。


ちょっと待って!インスタンスなしで使えるもの

「クラスのメンバー(変数やメソッド)を使うには、必ずインスタンスを作らないといけない」って話だったけど、実はそうじゃない例外があるんだ。それが今回の主役、staticキーワードだよ。

static(スタティックと読むよ)キーワードをメンバーに付けると、そのメンバーはインスタンスに属するんじゃなくて、クラスそのものに属することになるんだ。

これがどういうことか、具体的に見ていこう。


staticフィールド(クラス変数)

まずは変数から。staticな変数を**「staticフィールド」、または「クラス変数」**と呼ぶよ。

普通の変数(インスタンスフィールド)は、インスタンスを作るたびにそれぞれが固有の値を持つことができる。例えば、Carクラスがあったとして、インスタンスごとに色や車種が違うようにね。

Java

class Car {
    String color; // インスタンスフィールド

    Car(String c) {
        this.color = c;
    }
}

public class Main {
    public static void main(String[] args) {
        Car car1 = new Car("赤");
        Car car2 = new Car("青");

        System.out.println("car1の色: " + car1.color); // 出力: car1の色: 赤
        System.out.println("car2の色: " + car2.color); // 出力: car2の色: 青
    }
}

でも、staticを付けたクラス変数は、そのクラスのインスタンスがいくつあっても、すべてのインスタンスで同じ値を共有するんだ。例えるなら、クラス全員で使う共有ロッカーみたいなもの。

Java

class Student {
    String name;
    static String schoolName = "宇宙学園"; // staticフィールド(クラス変数)

    Student(String n) {
        this.name = n;
    }

    void displayInfo() {
        System.out.println("名前: " + this.name + ", 学校名: " + schoolName);
    }
}

public class StaticFieldExample {
    public static void main(String[] args) {
        Student s1 = new Student("タロウ");
        Student s2 = new Student("ハナコ");

        s1.displayInfo(); // 名前: タロウ, 学校名: 宇宙学園
        s2.displayInfo(); // 名前: ハナコ, 学校名: 宇宙学園

        // schoolNameはクラスに属するので、インスタンスを作らなくても直接クラス名でアクセスできる
        System.out.println("学園の名前は: " + Student.schoolName); // 出力: 学園の名前は: 宇宙学園

        // staticフィールドの値を変更すると、すべてのインスタンスに影響する
        Student.schoolName = "未来大学";
        s1.displayInfo(); // 名前: タロウ, 学校名: 未来大学
        s2.displayInfo(); // 名前: ハナコ, 学校名: 未来大学
    }
}

この例でわかるように、staticschoolNameStudentクラスに直接結びついているから、Student.schoolNameという形でインスタンスを作らずにアクセスできるし、値を変更すれば、すべてのStudentインスタンスから参照されるschoolNameも変わるんだ。

paizaで実行した結果


staticメソッド(クラスメソッド)

変数と同じように、メソッドにもstaticを付けることができるよ。staticなメソッドを**「staticメソッド」、または「クラスメソッド」**と呼ぶんだ。

普通のメソッド(インスタンスメソッド)は、インスタンスを作ってからじゃないと呼び出せないよね。例えば、car1.run()みたいに。

でも、staticメソッドは、インスタンスを作らなくてもクラス名を使って直接呼び出すことができるんだ。

一番身近な例は、これまでずっと使ってきたmainメソッドだよ!

Java

public class MyProgram {
    public static void main(String[] args) { // ここにstaticが付いてる!
        System.out.println("プログラム開始!");
        // このmainメソッドは、MyProgramのインスタンスを作らなくても実行されるよね。
        // その理由は、mainメソッドがstaticだからなんだ!
    }
}

paizaで実行した結果

他にも、よく使うstaticメソッドの例として、Javaの標準ライブラリにあるMathクラスのメソッドがあるよ。

Java

// Mathクラスは、数学的な計算をするためのメソッドをまとめたクラスだよ
// 例えば、絶対値を計算するabsメソッドや、平方根を計算するsqrtメソッドなど
public class StaticMethodExample {
    public static void main(String[] args) {
        // インスタンスを作らずに、クラス名.メソッド名で呼び出せる!
        double value = Math.abs(-10.5); // 絶対値
        System.out.println("絶対値: " + value); // 出力: 絶対値: 10.5

        double sqrtValue = Math.sqrt(25.0); // 平方根
        System.out.println("平方根: " + sqrtValue); // 出力: 平方根: 5.0
    }
}

staticメソッドは、インスタンスの固有の状態(インスタンスフィールドの値)に依存しない処理に使われることが多いんだ。例えば、ユーティリティメソッド(補助的な機能を提供するメソッド)なんかでよく見かけるよ。

注意点として、staticメソッドの中から、staticではないインスタンスフィールドやインスタンスメソッドを直接使うことはできないんだ。 なぜなら、staticメソッドが呼び出される時、まだインスタンスが存在しない可能性があるからだよ。

paizaで実行した結果


staticな初期化ブロック

staticフィールドの初期化は、宣言時に直接行ってもいいんだけど、ちょっと複雑な初期化が必要な場合は、static初期化ブロックを使うこともできるんだ。

これはクラスがメモリにロードされる際に、一度だけ実行される特別なブロックだよ。

Java

class Config {
    static String databaseUrl;
    static int maxConnections;

    // static初期化ブロック
    static {
        System.out.println("Configクラスがロードされました。static初期化ブロックが実行されます。");
        databaseUrl = "jdbc:mysql://localhost:3306/mydb";
        maxConnections = 10;
        // 実際にはここで設定ファイルから読み込むなどの処理を行うこともできる
    }

    void displayConfig() {
        System.out.println("DB URL: " + databaseUrl + ", Max Connections: " + maxConnections);
    }
}

public class StaticInitBlockExample {
    public static void main(String[] args) {
        System.out.println("--- mainメソッド開始 ---");
        // Configクラスが初めて使われる(ロードされる)と、static初期化ブロックが実行される
        Config c1 = new Config();
        c1.displayConfig();

        System.out.println("--- 2つ目のインスタンス作成 ---");
        Config c2 = new Config(); // 2つ目のインスタンス作成時もstatic初期化ブロックは実行されない
        c2.displayConfig();
    }
}

この例では、Configクラスが初めて使われる(例えば、new Config()でインスタンスが作られたり、Config.databaseUrlのようにstaticメンバーにアクセスされたり)と、そのクラスがメモリにロードされる際に、static { ... }ブロックが一度だけ実行されるんだ。その後、何度インスタンスを作っても、このブロックが再度実行されることはないよ。

paizaで実行した結果


staticを使うのはどんな時?

ここまでで、staticキーワードが何をするものか、なんとなくわかってきたかな?じゃあ、具体的にどんな時にstaticを使うと便利なのか見てみよう。

  1. 全てのインスタンスで共有する値:
    • 会社の名前、円周率(Math.PIのように)、プログラムのバージョン番号など、オブジェクトごとに値が変わらないもの
    • 例: public static final double PI = 3.14159; (finalは定数だよ。これもまた別の機会に!)
  2. インスタンスを作らずに実行したい処理:
    • ユーティリティメソッド(補助的な機能): 文字列を操作するメソッド、数値計算のメソッドなど。
    • ファクトリメソッド: 特定のインスタンスを生成して返すメソッド(デザインパターンの一つ)。
    • メインメソッド (public static void main(String[] args))。
  3. インスタンスの状態に依存しない処理:
    • 特定のインスタンスの状態(フィールドの値など)を使わないメソッド。

まとめ

今回の記事では、staticキーワードについて掘り下げてみたよ。

  • staticキーワードが付いたメンバーは、インスタンスではなくクラスそのものに属する
  • staticフィールド(クラス変数)は、そのクラスのすべてのインスタンスで同じ値を共有する。インスタンスを作らなくても、クラス名.変数名でアクセスできる。
  • **staticメソッド(クラスメソッド)**は、インスタンスを作らなくてもクラス名を使って直接呼び出せる。インスタンスの状態に依存しない処理に使われることが多い。
  • static初期化ブロックは、クラスがメモリにロードされる際に一度だけ実行される
  • staticなメンバーは、共有したいデータや、インスタンスなしで実行したい処理に使うと便利だよ。

これで、Javaのオブジェクト指向における「クラス」と「インスタンス」、そして「static」の概念が少しはっきりしてきたかな?

クラスとオブジェクトの概念 – オブジェクト指向の入り口 | ToolDocs

コメント

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