immutable class

immutable(不変)という意味
・fieldをfinal定義
・setterを排除
・classをfinal定義（setterを追加できなくするため）
・getterはnewして別インスタンスとして返す
```java
final class ImmutableClass {
    final String str;
    ImmutableClass(String str) {
        this.str = str;
    }
    String getStr() {
        return new String(str);
    }
    void method(String varName) {
        System.out.println(varName + " identityHashCode:" + System.identityHashCode(this) + " " + this.toString());
        System.out.println(varName + " HashCode:" + this.hashCode() + " " + this.toString());
        System.out.println(varName + ".str identityHashCode:" + System.identityHashCode(this.str) + " " + this.str.toString());
        System.out.println(varName + ".str HashCode:" + this.str.hashCode() + " " + this.str.toString());
    }
}
class ImmutableSubClass extends ImmutableClass {    //err
    ImmutableSubClass(String str) {
        super(str);
        this.str = str;    //err
    }
    void setStr(String str) {
        this.str = str;    //err
    }
}
public class SampleProject {
    public static void main(String[] args) {
        ImmutableClass ic = new ImmutableClass("im");
        ic.method("ic");
        String s = ic.getStr();
        method("s",s);
        ic.str = "change";     //err
        int i1 = 1;
        int i2 = 1;
        method("i1",i1);
        method("i2",i2);
        i1 = 2;
        method("i1",i1);
        method("i2",i2);
    }
    static void method(String varName, Object o) {
        System.out.println(varName + " identityHashCode:" + System.identityHashCode(o) + " " + o.toString());
        System.out.println(varName + " HashCode:" + o.hashCode() + " " + o.toString());
    }
}
```
```
C:\Users\java\Documents\NetBeansProjects\SampleProject\src\sampleproject\SampleProject.java:23: エラー: final ImmutableClassからは継承できません
class ImmutableSubClass extends ImmutableClass {
C:\Users\java\Documents\NetBeansProjects\SampleProject\src\sampleproject\SampleProject.java:26: エラー: final変数strに値を代入することはできません
        this.str = str;
C:\Users\java\Documents\NetBeansProjects\SampleProject\src\sampleproject\SampleProject.java:29: エラー: final変数strに値を代入することはできません
        this.str = str;
C:\Users\java\Documents\NetBeansProjects\SampleProject\src\sampleproject\SampleProject.java:38: エラー: final変数strに値を代入することはできません
        ic.str = "change";
エラー4個
```
```java
package sampleproject;

import java.util.Date;
final class ImmutableClass {
    final String str;
    ImmutableClass(String str) {
        this.str = str;
    }
    String getStr() {
        return new String(str);
    }
    void method(String varName) {
        System.out.println(varName + " identityHashCode:" + System.identityHashCode(this) + " " + this.toString());
        System.out.println(varName + " HashCode:" + this.hashCode() + " " + this.toString());
        System.out.println(varName + ".str identityHashCode:" + System.identityHashCode(this.str) + " " + this.str.toString());
        System.out.println(varName + ".str HashCode:" + this.str.hashCode() + " " + this.str.toString());
    }
}
public class SampleProject {
    public static void main(String[] args) {
        ImmutableClass ic = new ImmutableClass("im");
        ic.method("ic");
        String s = ic.getStr();
        method("s",s);
    }
    static void method(String varName, Object o) {
        System.out.println(varName + " identityHashCode:" + System.identityHashCode(o) + " " + o.toString());
        System.out.println(varName + " HashCode:" + o.hashCode() + " " + o.toString());
    }
}
```
```
ic identityHashCode:796533847 sampleproject.ImmutableClass@2f7a2457
ic HashCode:796533847 sampleproject.ImmutableClass@2f7a2457
ic.str identityHashCode:546718765 im
ic.str HashCode:3364 im
s identityHashCode:167185492 im   //getterから取得したStringは別インスタンス
s HashCode:3364 im      
```
primitive variantは参照型ではなく、値そのものを指している。
値を変更するとメモリの別領域がとられる。
つまり、インスタンス自体を変更することができない。
immutable（不変）である。

```java
public class SampleProject {
    public static void main(String[] args) {
        int i1 = 1;
        int i2 = 1;
        method("i1",i1);
        method("i2",i2);
        i1 = 2;
        method("i1",i1);
        method("i2",i2);
    }
    static void method(String varName, Object o) {
        System.out.println(varName + " identityHashCode:" + System.identityHashCode(o) + " " + o.toString());
        System.out.println(varName + " HashCode:" + o.hashCode() + " " + o.toString());
    }
}
```
```
i1 identityHashCode:249515771 1
i1 HashCode:1 1
i2 identityHashCode:249515771 1
i2 HashCode:1 1
i1 identityHashCode:748658608 2   //1→2でidentityHashCodeが変わった。つまり別領域がとられた
i1 HashCode:2 2
i2 identityHashCode:249515771 1
i2 HashCode:1 1
```