Javaのstaticな話

# はじめに
この記事は<a href="https://qiita.com/advent-calendar/2017/microad">MicroAd Advent Calendar 2017</a>の18日目の記事です。

普段そこまで意識することがないのか、あるのか、
今語らないと今後語ることはないでしょう、java における static のイマサラな話をしてみようと思います。

# ゴール
たかが static されど static、
簡単なクイズを書きながら、java における static なモノをこそこそと、今一度簡単に整理してみること。

# static フィールド
そもそも static は 「静的」 を意味します。~~こそこそ。~~
「動的ではない」ということで、そのフィールドはいくらインスタンスをたくさん生成したとしても、クラスにたった１つです。
複数のインスタンスの間で共有されつづける情報、共有資源にして欲しいフィールドに static をつけます。```クラス名.フィールド名``` で呼びます。インスタンスを生成して呼び出しても同じモノにアクセスできます。

定数定義の際に```final static``` で宣言することで、new する度に同じ値がインスタンスに複製されることが防止され、メモリの節約に役立ちます。

```java
public final static String KEY = "happy-toilet";
```
どこにいても呼び出すことができるハッピートイレの固定値です。

# static メソッド（クラスメソッド)
static メソッドは、そのものがクラスのインスタンスではなく、クラスに属します。
呼び出しは```クラス名.メソッド名```、関数型インターフェースのメソッド参照の場合は```クラス名::メソッド名```で直接呼び出しができます。
static フィールドとともに、静的メンバと呼ばれます。
static が付かない一般のメソッドは非 static メソッド、インスタンスメソッドと呼びます。

以下は java8 以降の、関数型インターフェースのメソッド参照における static メソッドとインスタンスメソッドの呼び出しの違いです。

```java:MethodReference.java
public class MethodReference {

  public static void main(String[] args) {
    // static メソッド
    wakeUp(MethodReference::printWakeUp);

    System.out.print(" and ");

    // インスタンスメソッド
    MethodReference mr = new MethodReference();
    mr.goToilet(mr::printGoToilet);
  }

  interface Human {
    void doSomething();
  }

  static void wakeUp(Human human) {
    human.doSomething();
  }

  static void printWakeUp() {
    String wakeUp = "wake up";
    System.out.print(wakeUp);
  }

  void goToilet(Human human) {
    human.doSomething();
  }

  void printGoToilet() {
    String toilet = "happy toilet";
    System.out.print(toilet);
  }
}
```
結果は <font color="white">wake up and happy toilet</font> です。

### オーバーライドできない

```java
public class StaticPractice {

  public static void main(String[] args) {

    Human developer = new Developer();

    System.out.println(developer.getMorning());

  }
}

class Human {
  static String morning = "Happy Toilet";

  static String getMorning() {
    return morning;
  }
}

class Developer extends Human {
  static String morning = "Happy Coding";

  static String getMorning() {
    return morning;
  }
}
```
もちろん結果は <font color="white">Happy Toilet</font> です。
<br>
<br>
`Developer developer = new Developer();` に直すと、一応 Happy Coding はできます。

しかし、ここでは`オーバーライドできない`を表すためだけにインスタンスを作ってそのインスタンスから呼び出しをしていますが、そもそもの話 static method は

```.java
 Human.getMorning();
 Developer.getMorning();
```

と、インスタンスを経由せずにクラスそのものからの参照が望ましいです。

実際、上記のコードをそのまま IntelliJ に移してみると

<img width="694" alt="alert.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194231/39136d80-e063-3be8-1b22-bb29b40dee6d.png">

`class itself から参照されていない static method` として注意されます.

(Special thanks to @kawamnv さん)

### public static void main(String [] args)
メインメソッドが呼び出される時、まだメモリにインスタンスは存在していないため、メインメソッドはそれを含んでいるクラスがインスタンス化されていなくても、実行される必要があるからです。

# static クラス(static インナークラス)
クラスの中のクラス、インナークラスには三種類があり、メンバクラス、ローカルクラス、匿名クラスがあります。
static メンバクラスは、メンバクラスの一つで、宣言場所はクラスブロックの中（フィールドとメソッドと同じ位置）です。
しかし厳密には、static メンバクラスはインナークラスとは呼び難く、まったく別のクラスと表現した方が正しいでしょう。

インナークラスを包んでいるクラスを外部クラスと呼ぶと、
外部クラスやそのインスタンスとの関係が比較的薄く、外部クラスの static メンバにもアクセスできます。

他の static なモノ同様、```外部クラス名.メンバクラス名```で利用します。

```java:Outer.java
class Outer { // 外部クラス

  // メンバクラス➀ static クラス
  static class StaticInner {
    private Integer in;

    public Integer getIn() {
      return in;
    }

    public void setIn(Integer in) {
      this.in = in;
    }
  }

  // メンバクラス➁ 厳密的なメンバクラス
  class Inner {
    private String str;

    public String getStr() {
      return str;
    }

    public void setStr(String str) {
      this.str = str;
    }
  }
}
```

無関係なクラスかつメインメソッドでの呼び出しは以下の通りです。

```java:Execute.java
class Execute {
  public static void main(String[] args) {
    // static クラス
    Outer.StaticInner staticInner = new Outer.StaticInner();

    // 厳密的なメンバクラス
    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();
  }
}
```

上記の例に含めてみましたが、厳密なメンバクラスは、外部クラスから生み出される個々のインスタンスと強い結びつきを持つため、外部クラスのインスタンスがなければ new ができません。static なモノではないため、非 static メンバにもアクセスが許容されます。

# static イニシャライザ
```java
static {
  // 処理
}
```
static イニシャライザは、クラスロード（.class ファイルがロード）される際に、一度だけ、実行されるブロックです。
あるクラスをインスタンス化する前や、メインメソッドよりも前に呼び出し実行したい処理を記述します。
もちろん記述できるのは static なモノに限ります。

使い道あるかな？と思っていましたが、

```java
public final static String VALUE;

static {
  VALUE = makeValue();
} 

/**
 * 特定条件下で値を動的に生成する
 * @return value 生成した値
 */
private static String makeValue() {
  // omit
}
```

先日、ふとしたきっかけでこのような使い方が試せました。
「インスタンス化よりも早いタイミングで、最初に一度だけ新しい値を作っておいて」それを使い回す目的だったので、ちょうどよかったと思います。


### コンストラクタと static イニシャライザ

```java
class Something {

  void printA() {
    System.out.print("t");
  }

  void printB() {
    System.out.print("e");
  }

  Something () {
    System.out.print("l");
    printB();
  }

  static {
    System.out.print("i");
  }
}

class StaticTest {
  static {
    System.out.print("T");
  }

  public static void main(String [] args) {
    System.out.print("o");
    new Something().printA();
  }
}
```

結果は <font color="white">Toilet</font> です。
static イニシャライザは、new(インスタンス化) によってようやく呼び出されるコンストラクタよりも、早い段階で呼ばれることがわかります。

# static import 宣言
java5 以降に導入されました。

以下は<a href="https://qiita.com/1nagon/items/07ac1f9bc8c55dffc541">前回の投稿</a>の制約アノテーション作成時に使用したソースです。

```java:CustomSize.java
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = {CustomSizeValidator.class})
public @interface CustomSize {
  // omit
}
```
実際```ElementType```と```RetentionPolicy```は長いパッケージ名を持つ enum なので、上記のようにすっきりと記述したりします。

外部クラスの static メンバでしたら、別に enum ではなくても利用できます。

```java
import static java.lang.System.*;
import static java.lang.Math.*;
```


# おわりまして
朝一のトイレほど、文法の基礎を再確認することはとても大事です（こそこそ）


以上