FC2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »Javaライブラリ
このページの記事一覧

【Java】ジェネリクスで動的に配列を生成する  


 C# を使ってるとジェネリック型でも「T[] arr = new T[5];」のように簡単に配列を生成できるので、つい Java でもやろうとしてしまうね(笑)。残念ながら Java ではそういう書き方はできないのと、プリミティブ型はジェネリクスには当てはめられない欠点があるので、専用メソッドを作って置くと便利だ。型変換については必要なだけオーバーロードでも作るしかないが、とりあえず簡単な例を挙げておこう。応用すれば色々役に立つだろう。


(※) Java openjdk 9 (build 9+181)[paiza.io] / Android Studio 3.1.2 [Java 1.7] / Windows10(x64) で確認



■ジェネリクスで動的に配列を生成する

●ジェネリクスで配列を動的に生成する(関数定義)
import java.lang.reflect.Array;

//1次元配列を生成する
@SuppressWarnings("unchecked")
public static final <T> T[] newArray(final int length, final T[] type) {
return (T[]) Array.newInstance(type.getClass().getComponentType(), length);
}

//2次元配列を生成する
@SuppressWarnings("unchecked")
public static final <T> T[][] newArray(final int y, final int x, final T[] type) {
return (T[][]) Array.newInstance(type.getClass().getComponentType(), y, x);
}

//3次元配列を生成する
@SuppressWarnings("unchecked")
public static final <T> T[][][] newArray(final int z, final int y, final int x, final T[] type) {
return (T[][][]) Array.newInstance(type.getClass().getComponentType(), z, y, x);
}

●使用例(メインでのコードなど)
String[] arr1 = newArray(5, new String[0]);  //new String[5] と同じ
System.out.println("length = " + arr1.length);
System.out.println();

String[][] arr2 = newArray(2, 5, new String[0]); //new String[2][5] と同じ
System.out.println("y length = " + arr2.length);
System.out.println("x length = " + arr2[0].length);
System.out.println();

String[][][] arr3 = newArray(3, 2, 5, new String[0]); //new String[3][2][5] と同じ
System.out.println("z length = " + arr3.length);
System.out.println("y length = " + arr3[0].length);
System.out.println("x length = " + arr3[0][0].length);
System.out.println();

length = 5

y length = 2
x length = 5

z length = 3
y length = 2
x length = 5

 引数の数値は次元数だが、type の引数に「new String[0]」を与えているのに注意しよう。これは配列そのものを渡しているわけでなく、配列の要素の型を取得して、ジェネリクスに当てはめるために使用するものだ。この方法はジェネリクスの型を取得する裏技的な手法として Java では良く使われる(単一で型を取得するメソッドはないが、配列で要素の型を取得するメソッドはあるため(Class.getClass().getComponentType())。「T...」みたいな可変長引数でも良い)。List を配列に変換するメソッド「List.toArray(new String[0])」を使ったことがあるかも知れないが、それと用法は同じだ。なので要素の数は0で良い。



■Integer[] → int[] 変換

 次に int[] を生成する方法を考えてみよう。残念ながら Java では元々プリミティブ型(int, float, boolean など)はジェネリクスに使えないという欠点がある。なのでとりあえずラッパークラスの Integer の配列で生成し、int[] 型に変換するという方法をとれば良い。あまりスマートではない気もするが、簡単なのでロジックで悩むことは無いだろう。

●Integer[] → int[] に変換する(関数定義)
//Integer[] → int[] に変換する
public static final int[] toIntArray(final Integer[] src) {
final int len = src.length;
final int[] dst = new int[len];
for (int i = 0; i < len; i++)
dst[i] = (src[i] == null) ? 0 : src[i];
return dst;
}

●使用例(メインでのコードなど)
//Integer[] で生成(※要素が null なので使う際は注意)
Integer[] tmp = newArray(5, new Integer[0]);
for (int i = 0; i < tmp.length; i++)
tmp[i] = i; //連番で要素を初期化

//Integer[] → int[] に変換
int[] arr = toIntArray(tmp);
System.out.println("length = " + arr.length);

//要素を結合して表示
String s = "";
for (int e : arr) {
if (s.length() > 0)
s += ", ";
s += e;
}
System.out.println(s);

length = 5
0, 1, 2, 3, 4

 またはラムダ式の使える環境(Java 1.8 / Android 7.0[API 24])なら「Integer[] → int[] 変換」を以下のようにも書ける。

●ラムダ式(steam)を使った「Integer[] → int[] 変換」
import java.util.Arrays;

//Integer[] → int[] に変換
int[] arr = Arrays.stream(tmp).mapToInt(e -> e).toArray(); //Java 1.8 / Android 7.0[API 24]

 ラムダ式は Java 1.8 以降、Arrays.steam() は Android 7.0[API 24] 以降なので、スマホの古い機種も対応させたいなら使わない方が良いかも知れない(Android って現時点ではまだ Java 1.7 が多いので)。Java のジェネリクスはプリミティブ型が使えないのが痛いが(だから配列系のメソッドにはオーバーロードが鬼のようにある(笑))、他のプリミティブ型も同じようにラッパークラスを経由すれば、動的生成も可能だ。簡単なのでやってみると良いだろう。


(関連記事)
【Java】配列, リスト(List), 連想配列(Map) の初期化
【Java】配列要素の反転(reverse)
【Java】2次元配列のソート


スポンサーサイト

category: Java

thread: プログラミング

janre: コンピュータ

tag: Javaライブラリ 
tb: 0   cm: --


プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop