Developer

【はじめてのJava】static変数の注意点【オブジェクトとクラス編】
2021.03.31
Lv1

【はじめてのJava】static変数の注意点【オブジェクトとクラス編】

はじめてのJava

このシリーズでは、初めてJavaやプログラミングを勉強する方向けに、Javaによるプログラミングの基礎を説明していきます。
目標レベルは、Javaの資格試験の一つである「Oracle Certified Java Programmer, Silver」(通称Java Silver)に合格できる程度の知識の習得です。
はじめてJavaやプログラムに触れる方にもできるだけわかりやすい解説を心がけていきます。


オブジェクトとクラス編

オブジェクトとクラス編では、Javaを扱う上で非常によく出てくる「オブジェクト」や「クラス」について扱っていきます。

前回は「static変数」について扱いました。

今回は「static変数の注意点」について扱っていきます。


目次


static変数

 static変数 とは変数の一種で、同じクラスを基にして作られたインスタンス同士で共有される変数のことです。

詳しくは前回の記事で説明しています。


static変数の注意点

static変数については、注意をしなければならない点があります。それは、やたら滅多とstaticをつけるとオブジェクト指向ではなくなってしまうということです。

一見するとどういうことか分かりづらいので、具体例を見ていきましょう。

コマンドプロンプトや統合開発環境(eclipseなど)が表示してくるエラーの一種に、以下のようなコンパイルエラーがあります。

この場合、実はspeedにstaticをくっつけると、一応コンパイルエラーが解消します。

一見すると、エラーさえ解決すれば問題なさそうに思うかもしれません。しかし本当にそうでしょうか。


staticではないspeed

まずは、staticではないspeedの場合を考えてみましょう。クラスとしては以下の通りです。

class Car{
  double speed;
  String color;
}

これをインスタンス化します。今回は2台インスタンス化しましょう。

ソースコードは以下の通りです。

public class MyCarDrive{
  public static void main(String[] args){
    Car car1 = new Car();
    Car car2 = new Car();
  }
}

図にすると以下のような状態です。


2台の車をインスタンス化できたら、car1のcolorをredに、car2のcolorをblueに設定してみましょう。

ソースコードは以下の通りです。

public class MyCarDrive{
  public static void main(String[] args){
    Car car1 = new Car();
    Car car2 = new Car();

    car1.color = "red";  //追加
    car2.color = "blue"; //追加
  }
}

図にすると以下のような状態です。


2台のcolorをそれぞれ設定できたら、car1のspeedだけ50.0に設定してみましょう。

ソースコードは以下の通りです。

public class MyCarDrive{
  public static void main(String[] args){
    Car car1 = new Car();
    Car car2 = new Car();

    car1.color = "red";
    car2.color = "blue";

    car1.speed = 50.0; //追加
  }
}

図にすると以下のような状態です。


表示部分を追加して実行すると、 car1はredで50.0、car2はblueで0.0 になっていることが確認できます。

public class MyCarDrive{
  public static void main(String[] args){
    Car car1 = new Car();
    Car car2 = new Car();

    car1.color = "red";
    car2.color = "blue";

    car1.speed = 50.0;

    /* ここから */   
    System.out.print(car1.color);
    System.out.print("->");
    System.out.print(car1.speed);
    
    System.out.println(); //改行
    
    System.out.print(car2.color);
    System.out.print("->");
    System.out.print(car2.speed);
    /* ここまで追加 */
  }
}

実行結果は以下の通りです。


staticなspeed

続けて、staticなspeedの場合を考えてみましょう。クラスとしては以下の通りです。

class BadCar{
  static double speed;
  String color;
}

先ほどと同じく、インスタンス化します。今回も2台インスタンス化しましょう。

ソースコードは以下の通りです。

public class BadCarDrive{
  public static void main(String[] args){
    BadCar car1 = new BadCar();
    BadCar car2 = new BadCar();
  }
}

図にすると以下のような状態です。クラス名がCarからBadCarに変更になり、speedにstaticが付いた以外は先ほどとほぼ同じ状況です。


2台の車をインスタンス化できたら、先ほど同様、car1のcolorをredに、car2のcolorをblueにしてみます。

ソースコードは以下の通りです。staticではない場合とほとんど変わりません。

public class BadCarDrive{
  public static void main(String[] args){
    BadCar car1 = new BadCar();
    BadCar car2 = new BadCar();

    car1.color = "red";  //追加
    car2.color = "blue"; //追加
  }
}

図にすると以下の状態です。先ほどと変わりません。

2台のcolorをそれぞれ設定できたら、今回もcar1のspeedだけ50.0に設定し、2台のcolorとspeedを表示してみましょう。

public class BadCarDrive{
  public static void main(String[] args){
    BadCar car1 = new BadCar();
    BadCar car2 = new BadCar();

    car1.color = "red";
    car2.color = "blue";

    car1.speed = 50.0; //追加。car1のspeedだけ50.0に設定。car2はそのまま。

    /* ここから */   
    System.out.print(car1.color);
    System.out.print("->");
    System.out.print(car1.speed);
    
    System.out.println(); //改行
    
    System.out.print(car2.color);
    System.out.print("->");
    System.out.print(car2.speed);
    /* ここまで追加 */
  }
}

すると、なんと今回は、 speedを50.0にしたのはcar1だけなのに、car2のspeedも50.0になっている ことが確認できます。

図にすると以下のような状態です。

speedにstaticを付けた結果、 car1にとってのspeedとcar2にとってのspeedは同じもの になりました。

つまり、どれか1台がspeedを変更すると全台ともに同じspeedになるようになっています。誰かがアクセルを踏めば、全台加速する状態です。恐ろしいですね。

これではオブジェクト指向としては正しくありません。staticは必要な時にだけつけるようにします。


おまけ:staticがついていないと怒られた場合の対処法

変数にstaticがついていないと怒られた場合は、以下の2通りの解決方法が考えられます。

1.該当の変数にstaticをつける
2.該当の変数を定義しているクラスをインスタンス化して、その後インスタンス変数として利用する

1.の方法はこの記事で説明した通り、安易に行うとオブジェクト指向ではなくなります。
2.の方法はインスタンス化の方法の記事で紹介した通りです。一見するとソースコードの量は増えますが、2の方がオブジェクト指向に沿った解決方法です。

多くの統合開発環境(eclipseなど)では、エラー解決の方法の1つとして提案してくることが多いです。一見簡単な解決方法に見えますが、使わないほうが良い場面の方も多々あるので注意してください。


まとめ

static変数は同じクラスから作られたオブジェクト同士で共有される。
static変数を変更すると、同じクラスを基にしている全てのオブジェクトが影響を受ける。

次回

次回はメソッドについて触れていきます。


はじめてのJavaシリーズの目次はこちら
プログラムの作り方編はこちら


java 11 の練習問題一覧はこちら
はじめてのJavaシリーズの練習問題一覧はこちら