Shortの比較でNullPointerExceptionになって知ったオートボクシング

# ラッパークラスで値を比較するときは`equals`を使う
Stringの比較でよく言われています。
比較で`==`を使うと
ラッパーなどの**参照型の場合は参照先**を比較、**プリミティブ型の場合は値**を比較します。

```java
String hoge = "hoge";
String fuga = "hogehoge";
fuga = fuga.substring(4); // << "hoge"になる

// 参照先を比較するので「false」になる
boolean isEqual1 = hoge == fuga;

// 値を比較するので「true」になる
boolean isEqual2 = hoge.equals(fuga);
System.out.print(isEqual2);
```

# Shortを比較するのに`==`を使っても「-128~127」の範囲は値を比較してくれる
うっかりShort(shortのラッパー)を`==`で比較していたけど途中まで気が付かなかった、気が付いたのは値が200ぐらいになった時。へぇー知らなかった・・・とはいえ`equals`を使うべきですね。

```java
Boolean isEquala = null;
// 「-128~127」の範囲外なので「false」になる
Short a1 = -129;
Short a2 = -129;
isEqual = a1 == a2;
// 「-128~127」の範囲内なので「true」になる
Short b1 = -128;
Short b2 = -128;
isEqual = b1 == b2;
// 「-128~127」の範囲内なので「true」になる
Short c1 = 127;
Short c2 = 127;
isEqual = c1 == c2;
// 「-128~127」の範囲外なので「false」になる
Short d1 = 128;
Short d2 = 128;
isEqual = d1 == d2;
```

たぶん、Integerと同じ理由だと思われます。
> intからIntegerへは「new Integer()」でなく「Integer.valueOf()」が使われるから。
> これは（現状では）-128～127の範囲ではキャッシュされたIntegerを返すようになっているので、その範囲なら同一のインスタンスとなる。だから==で比較しても等しくなる。
> [Java型メモ(Hishidama's Java type Memo)](https://www.ne.jp/asahi/hishidama/home/tech/java/type.html)

# Shortの比較で`==`を使っていてもNullPointerExceptionになる
意外だった・・・というか納得できない

```java
Short a = null;
Boolean isOne = null;
// 想像通りにNullPointerExceptionになる
isOne = a.equals(1);
// 想像通りに「true」になる
isOne = a == null;
// 意外にNullPointerExceptionになる！
isOne = a == 1;
// これはNullPointerExceptionにならずに「false」になる
isOne = a == new Short("1");
// これも「false」になる
Integer i = 1;
isOne = a == new Short(i.shortValue());
```

# プリミティブ型とラッパークラスを自動変換するボクシング変換というものがある
JDK1.5からできるようになったそうで、そんな名前があることを知らなかった。

```java
// ラッパークラスに普通の代入
Short a1 = new Short("1000");
// オートボクシング：プリミティブ型をラッパークラスに自動変換
Short a2 = 1000; // classファイルを逆コンパイルするとこうなる >> Short a2 = Short.valueOf((short)1000);

// プリミティブ型に普通の代入
short b1 = a1.shortValue();
// アンボクシング：ラッパークラスをプリミティブ型に自動変換
short b2 = a2; // classファイルを逆コンパイルするとこうなる >> short b2 = a2.shortValue();
```

## ボクシング変換されているかを確かめたくてShortの比較で`==`を使ったところを逆コンパイルしてみた
ボクシング変換されているかは逆コンパイルするとわかるらしい、[だから逆コンパイルしてみた。](https://qiita.com/ponsuke0531/items/8a6bcb483607a7330ba0)

> コンパイルしたものを逆コンパイルして見ると、ただ単に変換メソッドに置き換えられているだけ…。
> [Java型メモ(Hishidama's Java type Memo)](https://www.ne.jp/asahi/hishidama/home/tech/java/type.html)

```java
isOne = a.equals(1);
// ↑これをコンパイルして逆コンパイルするとこうなる↓
isOne = Boolean.valueOf(a.equals(Integer.valueOf(1)));

isOne = a == null;
// ↑これをコンパイルして逆コンパイルするとこうなる↓
isOne = Boolean.valueOf(a == null);

isOne = a == 1;
// ↑これをコンパイルして逆コンパイルするとこうなる↓
isOne = Boolean.valueOf(a.shortValue() == 1);

isOne = a == new Short("1");
// ↑これをコンパイルして逆コンパイルするとこうなる↓
isOne = Boolean.valueOf(a == new Short("1"));

Integer i = 1;
isOne = a == new Short(i.shortValue());
// ↑これをコンパイルして逆コンパイルするとこうなる↓
Integer i = Integer.valueOf(1);
isOne = Boolean.valueOf(a == new Short(i.shortValue()));
```

## Shortをプリミティブ型と`==`で比較すると`shortValue()`が実行されるからNullPointerExceptionになる！
```java
a == 1;
// ↑は、こう↓なる
Boolean.valueOf(a.shortValue() == 1);
```

NullPointerExceptionになる理由は分かったけどなんでリテラルの数値の時だけ`shortValue()`なんだろう？
`a == new Short("1");`は、`Boolean.valueOf(a.shortValue() == new Short(i.shortValue()));`にならないんだろう？

そんな疑問に @swordone さんが教えてくれました。

ラッパークラス(参照型)をプリミティブ型と比較するとオートボクシングが行われるので、
比較対象が参照型であれば`.shortValue()`は実行されずNullPointerExceptionは発生しない。

```java
// 例えばこれは、比較対象がプリミティブ型なので
boolean isOne = a == (short) 1;
// オートボクシングが実行される(↓逆コンパイルした結果)
boolean isOne = a.shortValue() == 1;