基本型配列を引数にするときにNumberクラスを使うと型ごとにオーバーロードしなくて良くなるかも

概要: 基本型配列を引数にしてかつ様々な型に対応させたい
---

あまり需要ないかもしれませんが書いておきます。

Javaのプログラムで、あるメソッドの引数を数値基本型の配列で定義するとします。
ただし処理の内容は型によらず同じであり(例えば以下の様な文字列結合)、かつ実際には各要素にintが来るのかdoubleが来るのかわからない場合、果たしてどのようにメソッドを定義すればよいでしょうか。

例えば型に合わせてオーバーロード(多重定義)することにより対応させられるかもしれません。

```OverloadSample.java
/*
* 以下の3つのメソッドはこのままだと1つにはまとめられない
*/
// int型配列用
public void concatArray(int[] num) {
    String line = "";
    for(int i : num) line += i + ",";
    System.out.println(line.substring(0, line.length() - 1));
}

// double型配列用
public void concatArray(double[] num) {
    String line = "";
    for(double d : num) line += d + ",";
    System.out.println(line.substring(0, line.length() - 1));
}

// float型配列用
public void concatArray(float[] num) {
    String line = "";
    for(float f : num) line += f + ",";
    System.out.println(line.substring(0, line.length() - 1));
}

```

しかしこれを見て、『基本型に合わせてわざわざ多重定義する必要はない!!』と思った方はお気づきかもしれませんが**[`Number`型](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Number.html)にBoxingしてしまう**という方法があります。

`Number`は`Integer`や`Double`の親クラスで、型が不明な数値配列もまとめて扱うことができます。

```NumberSample.java
private String concatArray(Number[] numbers) {
    String line = "";
    for (Number number : numbers)
        line += number.toString() + ",";
    System.out.println(line.substring(0, line.length() - 1));
}
```

さらに数値以外の引数が来るなら、より抽象度を上げて`Object`配列を引数にする必要もあるでしょうが、数字だけであれば`Number`で十分かと思われます。また元の数値に戻すメソッド(`Number.intValue()`, `Number.doubleValue()`)もあります。

ただしNumberを直接`new`する時は、抽象メソッドである`Number.intValue()`や`Number.doubleValue()`の実装が必要です。

```NewNumber.java
Number number = new Number() {
    @Override
    public int intValue() {
         return 0;
    }
    ...
};
```


余談: そもそもJavaの配列は特殊なクラス
---

そもそものきっかけは、**配列のクラス名が分かれば、共通の親クラスを引数にするメソッドを書くことで、上記の要件を達成できるのではないのか**と考えたことでした。

Javaの配列は`Object`継承であり、ゆえに`Object`から継承されたメソッド群も使えます。しかし次のコードは何を出力するでしょうか?

```java:ArrayClassName.java
public class ArrayClassName() {
  public static void main(String args[]) {
    boolean[] b = { true, false };
    int[] i = { 1, 2, 3 };
    double[] d = { 1.11, 2.22, 3.33 };

    System.out.println(b.getClass());
    System.out.println(i.getClass());
    System.out.println(d.getClass());
  }
}
```

答えはこうです

```shell-session
class [Z
class [I
class [D
```

"Array"などと表示してくれるかと思いきや、何やら意味不明な文字列が出力されます。

実は**Javaの配列は`Object`継承でありながら、どのクラスやパッケージにも属さない特殊なクラス**だったのです!
(そんなこと大学の先生は一言も教えてくれなかったよ!!)
なんか言葉だけだと矛盾してしまうようですが本当です。

ではこの意味不明な文字列は何かというと、Javaの言語仕様に

> where the string "[I" is the run-time type signature for the Class object "array with component type int".

とあります。
意訳すると**『"[I"は『int型配列』のクラスオブジェクトの実行時型を表すシグネチャである』**となります。
シグネチャはJavaの内部処理的に振らているメソッドの識別コードのようなものですが、それがなぜ配列にフラレているのかまではわかりませんでした。

結局のところ、Javaで厳密に配列がどのような位置づけなのかはわかりませんでしたが、**クラスではないObject**というのが今の結論でしょうか。

たぶん間違っていると思いますので、ネットで資料が出てこないので誰か教えて。

参考
---

* [配列クラスのクラス名](http://oshiete.goo.ne.jp/qa/5759538.html)
* [10.8. Class Objects for Arrays - Java Platform Standard Edition 8 Documentation](http://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.8)
* [プリミティブ型配列の操作（結合・部分配列・サイズ変更）](http://qiita.com/landrunner/items/d4894b3bab649f64a674)
* [配列のキャスト](http://npnl.hatenablog.jp/entry/20080902/1220372739)