【Java】staticとfinalのお話

Javaを書いていると、
「定数値は大文字で宣言して、かつstaticとfinalをつけましょう」
ということが書いてあったりします。

まぁおまじないのようにふわっと理解していても良いんですが、
この機会に書いてみようと思います。

■staticって何?

直訳すると静的ですね。
(自分の機能の夕飯くらいどうでも良いんですが、
静的チェックとか静的コンパイルとか書いたときにたまに誤変換で出てくる性的チェック。
なんともアンニュイな気持ちになります)

Javaは基本的にクラスをインスタンス化して動きます。

そのため各インスタンス内で中身の状態は変化していきます。

たとえば以下のような人間クラスがあったとして

public class Human {
  private double height;
  private double weight;

  public double getHeight() {
    return height;
  }

  public double getWeight() {
    return weight;
  }

  public void setHeight(double height) {
    this.height = height;
  }

  public void setWeight(double weight) {
    this.weight = weight;
  }
}

Aさん、Bさんがパラメータを入力していった場合、
身長170cmのAさんが入力したHumanクラスのインスタンスのheightは170になり、
身長156cmのBさんが入力したHumanクラスのインスタンスのheightは156になります。

このように同じ変数heightでもインスタンス内で状態が動的に変わっていきます。

で、このstaticって何者かっていうと、「静的=動的でない」ものとして、
そのクラスに変わらない値として存在し続けてくれます。

public class Human {
  private static int AGE = 18;
  private double height;
  private double weight;

  public double getHeight() {
    return height;
  }

  public double getWeight() {
    return weight;
  }

  public void setHeight(double height) {
    this.height = height;
  }

  public void setWeight(double weight) {
    this.weight = weight;
  }
}

上記のように書いた場合、
private static int AGE = 18;
はすべてのインスタンスクラスで共通で利用され、変更もされません。
staticフィールドと呼ばれたりします。

そのため、今そこまで昔ほどシビアではなくなったと思いますが、
100個Humanクラスがインスタンス化されても、この
private static int AGE = 18;
のstaticフィールドは1個です。そのため、メモリ節約になります。
個人のどうでも良いアプリは別ですが、企業のアプリの場合は意識したほうが良いです。
塵も積もればなんとやらなので。。。

また、staticフィールドはオーバーライドされません(プチ重要)

たとえばこんなコードを書こうとしたとします。

public static void main(String[] args) {
    SuperHuman sh = new SuperHuman();
    System.out.println(sh.getAge());
}

public class Human {
  private static int AGE = 18;

  public static int getAge() {
    return AGE;
  }
}

public class SuperHuman extends Human {
  private static int AGE = 19;

  public int getAge() {
    return AGE;
  }
}

この用にHumanのgetAgeメソッドをstatic宣言した場合、
SuperHumanのメソッドpublic int getAge() {
とオーバーライドしようとすると、「オーバーライドできません」とコンパイルエラーになります。

そのため、特定のメソッド名のメソッドの返り値を担保させたい場合にも使えます。

■finalって何?

finalは一回しか代入が出来ない変数ですよというマークです。
private final int age = 18;
とあった場合、その後のプログラムで
age = 19;
と書いた場合、このタイミングでコンパイルエラーになります。

あと他には、メンバ変数をfinal宣言しておき、コンストラクタで代入するというのも良くあります。

一回インスタンス化したらその後はその変数の値を変更したくない場合に使います。

public class Human {
  private final double height;

  public Human(double height) {
    this.height = height;
  }

  public double getHeight() {
    return height;
  }
}

こんな使い方ですね。

こうすることで、一度初期化した値をそのインスタンスでは引きずり回します。

■staticとfinalの裏目的

ここまでstaticとfinalの振る舞いについて書いてきました。

書いてきたものはうそではないですし、目的もうそは書いていません。
staticとかfinalは自分以外の開発者に向けたメッセージとして用いるような気がします。

というのも、Javaってリフレクションがある以上、
privateメソッドも変数も直接アクセスして変更することが出来てしまいます。

極端finalをつけていてもリフレクションで値を変更することは出来なくはないです。

では意味がないのかというとそうではなく、

public static final int AGE = 18;
と書いてあった場合、
「staticって書いてあるから定数な!finalってつけてるんだから、中身を変更するんじゃねーぞ!!!」って意思表示になります。

抽象クラスのメソッドにstaticって付いていたら
「オーバーライドしてもこのメソッドは変えるなよ!!!変えたらどうなるか分からないからな!!!!」
みたいな話です。

複数人数で開発するときは意識して行いたいものですね。

 

コメント

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