Chapter 11

Java static

おでん
おでん
2021.08.14に更新

staticとは

staticとは、直訳で「静的」という意味です。つまり、不変なものです。
Javaでいうstaticはstatic修飾子を指します。
static修飾子は、メンバ(メンバ変数とメソッド)に付与します。
ここまでで、static修飾子が付与されたメンバは静的なもの ということが分かります。

メンバ変数の種類

メンバ変数には、以下の2種類あります。

  1. インスタンス変数(非staticなメンバ変数)
  2. static変数

メソッドも同じように2種類あります。

  1. インスタンスメソッド(非staticなメソッド)
  2. staticメソッド
記述 メンバ変数 メンバメソッド 別クラスでの呼び出し
static修飾子なし インスタンス変数 インスタンスメソッド インスタンス化必須
static修飾子あり static変数 staticメソッド インスタンス化不要

この2つの見分け方は簡単で、「static修飾子が付いているか、付いていないか」です。
インスタンス変数・インスタンスメソッドは、インスタンス生成ごとにそれぞれ持っています。
そのため、インスタンス化しなければ別クラスで呼び出すことができません。
インスタンス

参考:Javaの道

一方、static変数・staticメソッドは、クラスにたいして1つ持っています。
そのため、インスタンス化しなくても別クラスで呼び出すことができます。
インスタンス

参考:Javaの道

以下の例で確認しましょう。

InstanceStatice.java
public class InstanceStatic {
    //インスタンス変数の宣言と初期化
    int instanceVal = 10;
    
    //static変数の宣言と初期化
    static int staticVal = 100;
    
    //インスタンスメソッドの宣言
    void instanceMethod(){
      System.out.println(instanceVal);
    }
    
    //staticメソッドの宣言
    static void staticMethod(){
      System.out.println(staticVal);
    }
}
CallInstanceStatic.java
public class CallInstanceStatic {
  public static void main(String[] args){
    //InstanceStaticクラスのstatic変数を呼び出し
    System.out.println(InstanceStatic.staticVal);
    
    //InstanceStaticクラスのstaticメソッドを呼び出し
    InstanceStatic.staticMethod();
    
    //InstanceStaticクラスをインスタンス化しxに代入
    InstanceStatic x = new InstanceStatic();
    
    //xのインスタンス変数を呼び出し
    System.out.println(x.instanceVal);
    
    //xのインスタンスメソッドを呼び出し
    x.instanceMethod();
  }
}
結果
100
100
10
10

インスタンス変数とインスタンスメソッドは、インスタンス化の後で呼び出しているため、使用できています。
もし、インスタンス化していない場合は、参照できませんというコンパイルエラーとなります。

ちなみに同じクラス内では、インスタンス化しなくてもインスタンス変数・インスタンスメソッドを呼び出すことができます。
しかし、staticメソッドでインスタンス変数を参照する場合に限っては、インスタンス化が必要です。

InstanceStatice.java
public class InstanceStatic {
    //インスタンス変数
    int instanceVal = 10;
    //static変数
    static int staticVal = 100;
    //インスタンスメソッド
    void instanceMethod(){
      System.out.println(instanceVal);
    }
    //staticメソッド
    static void staticMethod(){
      System.out.println(staticVal);
    }

    //インスタンスメソッド→インスタンス変数 (問題なし)
    int A(){
      return instanceVal;
    }
    
    //インスタンスメソッド→static変数 (問題なし)
    int B(){
      return staticVal;
    }
    
    //staticメソッド→static変数 (問題なし)
    static int C(){
      return staticVal;
    }
    
    //staticメソッド→インスタンス変数 (コンパイルエラー)
    // static int D(){
    //   return instanceVal;
    // }
    
    //staticメソッド→インスタンス変数 (インスタンス化すれば問題なし)
    static int D(){
      InstanceStatic y = new InstanceStatic();
      return y.instanceVal;
    }
}

static・非staticなメンバの参照記述

staticメンバとインスタンスメンバの参照は以下のように記述します。

メンバ メンバ変数 メソッド
static クラス名.メンバ変数名 クラス名.メソッド名(引数)
インスタンス インスタンスアドレス値を格納する変数名.メンバ変数名 インスタンスアドレス値を格納する変数名.メソッド名(引数)

ここで、一度生徒の自己紹介の例を見てみましょう。

Student.java
public class Student {
  public static String race;
  public String name;
  public int age;
  public void Self(String mess){
    System.out.println("名前は" + name);
    System.out.println("年齢は" + age);
    System.out.println("自己紹介:" + mess);
    System.out.println("国籍:" + race);
    System.out.println("-------------------------");
  }
}
StudentMain.java
public class StudentMain {
  public static void main(String[] args){

    Student.race = "日本人";

    Student tanaka = new Student(); 
    Student suzuki = new Student(); 
  
    tanaka.name = "田中";
    tanaka.age = 29;

    suzuki.name = "鈴木";
    suzuki.age = 25;
  
    tanaka.Self("田中です");
    suzuki.Self("鈴木です");
  
  }
}

結果
名前は田中
年齢は29
自己紹介:田中です
国籍:日本人
-------------------------
名前は鈴木
年齢は25
自己紹介:鈴木です
国籍:日本人
-------------------------

ここで気になる点があります。
先程、staticメンバとインスタンスメンバの参照の記述書式を挙げました。
しかし、今回の例ではそれと異なる書式で記述されています。以下の箇所です。

Student.java
  public void Self(String mess){
    System.out.println("名前は" + name);
    System.out.println("年齢は" + age);
    System.out.println「」("自己紹介:" + mess);
    System.out.println("国籍:" + race);
    System.out.println("-------------------------");
  }

「name」「age」「race」はメンバ名のみで記述されています。
本来は以下のように記述すると思われます。

  • 「インスタンスアドレス値を格納する変数名.name」
  • 「インスタンスアドレス値を格納する変数名.age」
  • 「Student.race」

ただし、今回のように以下の点を満たしていれば、メンバ名のみで参照することが可能です。

  • 自インスタンスのインスタンスメンバを参照するとき
  • 自クラスのstaticメンバを参照するとき

上記の例だと、Selfメソッド実行時に「tanaka」や「suzuki」という自インスタンスを特定できています。
そのため、「name」や「age」は自インスタンスのインスタンスメンバを参照していることが分かります。
また、staticメンバの「race」は、Studentクラスという同じクラス内で参照しています。

これらのことから、最初に定義したstaticと繋がります。
つまり、どのインスタンスも静的で同じ値を持つものがstaticメンバです。(今回だとrace)
一方、それぞれのインスタンスが異なる値を持つものがインスタンスメンバ(非staticメンバ)です。(今回だとname,age)