【初心者向け】Javaでのクラス,インスタンス,staticの解説

# この資料について

「スッキリわかるJava入門 第2版」を使ってJavaの研修を行っています。
この本は、かなりわかりやすく書いていると考えていますが、それでもオブジェクト指向の説明に入り、「インスタンス」のあたりになると腹落ちしないことが多いようです。

書籍には次のように記載されています。

> 「クラスはプラモデル工場にある「金型」と同じと考えれば...」(P.302)
> 「仮想世界で活動するのは「 *インスタンス* 」であり、そのインスタンスを生み出すための金型が「 *クラス* 」である。」(P.303)

注: ここでいう「仮想世界」はJVMを意味しているものです。(P.283)

抽象的な話なので、イメージをつかむためにはよいと思います。
ただし、実際に使うとなると、もうちょっと具体的な説明が必要と考えています。

## 本解説の対象者

次の方を対象としています。

- Javaを学習中の初心者の方。
- インスタンス、staticについて、学習したものの、しっくりこない方。
- 特に「スッキリわかるJava入門 第2版」(以下、書籍)の第Ⅱ部を学習中の方。

## この資料の目的 と 範囲

次についてJVMのメモリ上でどういった動作をするかの概要を解説し、コーディングするために理解を深めてもらうことが目的です。

- クラス
- インスタンス
- static と 非static

尚、次については対象外とします。

- カプセル化, アクセス修飾子
- garbage collection
- 関数型
- class loader

# 解説

## 1.クラスのロード

クラスは、アプリケーションが使うことになったときに、JVMのメモリにロードされます。
クラスのロードは、Javaが行うのでプログラマは気にしなくてよいです。

```Cleric.java
class Cleric {
    private String name;
    private int hp;

    public Cleric(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }
    public String toString(){
        return this.name + " HP:" + this.hp;
    }
}
```
↑のイメージ↓
![Class1.png](https://qiita-image-store.s3.amazonaws.com/0/234166/1a1add71-3fea-13ae-3cd6-1389bc9508fe.png)

これだけだと、クラスをロードするだけでメンバは使えません。
インスタンス化されておらず、nameもhpも定義があるだけで、メモリ上にはnameもhpも領域は確保されていないためです。

## 2.インスタンス化

では、newして使ってみます。

```ClericQuest.java
class ClericQuest {
    public static void main(String[] args) {
        Cleric cleric1 = new Cleric("John", 50);//ここでnewする
        System.out.println(cleric1.getName());//newしたインスタンスにアクセス
    }
}
```
↑のイメージ↓
![Class2.png](https://qiita-image-store.s3.amazonaws.com/0/234166/f41016f4-eadc-f7c4-058a-8ce122a5a33b.png)
newすることで、インスタンスがJVMのメモリ上に確保されます。メンバもその中にあります。  
これで、nameやhpも、利用できますね。  


インスタンスは複数作成できます。

```ClericQuest.java
class ClericQuest {
    public static void main(String[] args) {
        Cleric cleric1 = new Cleric("John", 50); //1つめのnew
        Cleric cleric2 = new Cleric("Taro", 55); //2つめのnew
        Cleric cleric3 = new Cleric("Mary", 65535); //3つめのnew
        System.out.println(cleric1);
        System.out.println(cleric2);
        System.out.println(cleric3);
    }
}
```
↑のイメージ↓
![Class3.png](https://qiita-image-store.s3.amazonaws.com/0/234166/d0672eb0-763b-e77c-2697-520164de3010.png)


それぞれのインスタンスのメンバはメモリ上はそれぞれ別に確保されます。  
この例ですと、cleric1のnameは、cleric2のnameに影響しません。

## 3.staticは？

上記はstaticの説明を省いているので、staticについて説明します。

staticとは「静的」と訳されます。初めから確保されていて、増やしたり減らしたりできないことです。  
それに対し、「動的」(dynamic)とは、任意に増やしたり減らしたりできることです。  
これまでの説明は、newすることでインスタンスを増やすことができる、動的なメンバ(=非staticメンバ)についての説明でした。

staticのメンバは、クラスのロード時にJVMのメモリ上に確保されます。

```Cleric.java
class Cleric {
    private String name;
    private int hp;
    private static int countMember = 0; //Clericのインスタンスの数。static

    public Cleric(String name, int hp) {
        this.name = name;
        this.hp = hp;
        Cleric.countMember ++;
    }
    public String toString(){
        return this.name + " HP:" + this.hp;
    }
    public static int getCountMember(){
        return Cleric.countMember;
    }
}
```
```ClericQuest.java
class ClericQuest {
    public static void main(String[] args) {
        System.out.println("人数は" + Cleric.getCountMember());//0が表示される
        Cleric cleric1 = new Cleric("John", 50);
        Cleric cleric2 = new Cleric("Taro", 55);
        Cleric cleric3 = new Cleric("Mary", 65535);
        System.out.println(cleric1);
        System.out.println(cleric2);
        System.out.println(cleric3);
        System.out.println("人数は" + Cleric.getCountMember());//3が表示される
    }
}
```
↑のイメージ↓
![Class4.png](https://qiita-image-store.s3.amazonaws.com/0/234166/c0d2ce30-72b7-400a-a535-0ce2a38c2200.png)

インスタンス化してもstaticのメンバは増えません。

結果的に、staticのメンバは次の特徴があります。

1. インスタンスにはに紐づかない。クラスのみに紐づく。
2. インスタンス化(new)しなくても使える。
3. すべてのインスタンスで共用される。
4. staticメソッドからは、非staticメンバは(直接は)利用できない。
5. 継承できない。(サブクラスで同名の定義は可能だが、無関係。)

# 補足

## FAQ(聞かれそうな質問)

static ってインスタンスと紐づかないのであれば、クラスに入れる意味あるの？
→ カプセル化といったクラス設計について考えると、クラスのメンバにする意味が出てきます。

「1. インスタンスにはに紐づかない。」と言っているけど、「3. すべてのインスタンスで共用される。」と矛盾しない？
→「1. インスタンスにはに紐づかない」ため、public staticにするとプログラム全体で共用されますが、private staticにすると、同じクラスからしかアクセスできないためこのように記載ています。

「1. インスタンスにはに紐づかない」と言っているけど、「インスタンス」.「スタティックメンバ名」というように、記載できるよ。
→ 「インスタンス」.「スタティックメンバ名」という記述もコンパイルエラーにはなりませんが、正しいとは言えません。  
「クラス名」.「スタティックメンバ名」とすべき。(もちろん自分のクラスであれば、クラス名部分は不要。)

toStringつかってないじゃない？
→ それは今後のお勉強でのお楽しみ。

## ついでに

インスタンスの理解は、初期につまづくポイントの1つだと思います。  
これを理解すれば、他のJavaに似たプログラミング言語も理解できます。

クラス と インスタンスの説明としていますが、staticを理解することが、インスタンスの理解を深められると考えています。