現在のバージョン (Java 12) では、プリミティブ型を Java ジェネリックで表すことはできません。より具体的には、プリミティブ型を型引数として提供することはできません。(たとえば はできませんFoo<int>
。) また、型変数を式の型として使用できないため、配列を作成するnew
こともできません。new T[n]
したがって、これを行う理想的な方法はありません。
リフレクション ( ) を使用して合理的にこれを行うことは可能ですが、引数としてjava.lang.reflect.Array
a を指定する必要があります。Class
これがどのように行われるかの例を次に示します。
/**
* Unboxes a List in to a primitive array.
*
* @param list the List to convert to a primitive array
* @param arrayType the primitive array type to convert to
* @param <P> the primitive array type to convert to
* @return an array of P with the elements of the specified List
* @throws NullPointerException
* if either of the arguments are null, or if any of the elements
* of the List are null
* @throws IllegalArgumentException
* if the specified Class does not represent an array type, if
* the component type of the specified Class is not a primitive
* type, or if the elements of the specified List can not be
* stored in an array of type P
*/
public static <P> P toPrimitiveArray(List<?> list, Class<P> arrayType) {
if (!arrayType.isArray()) {
throw new IllegalArgumentException(arrayType.toString());
}
Class<?> primitiveType = arrayType.getComponentType();
if (!primitiveType.isPrimitive()) {
throw new IllegalArgumentException(primitiveType.toString());
}
P array = arrayType.cast(Array.newInstance(primitiveType, list.size()));
for (int i = 0; i < list.size(); i++) {
Array.set(array, i, list.get(i));
}
return array;
}
呼び出しの例:
List<Integer> list = List.of(1, 2, 3);
int[] ints = toPrimitiveArray(list, int[].class);
Array.set
拡張プリミティブ変換を実行することに注意してください。したがって、次のように機能します。
List<Integer> list = List.of(1, 2, 3);
double[] doubles = toPrimitiveArray(list, double[].class);
ただし、縮小変換は実行されないため、次の例では例外がスローされます。
List<Integer> list = List.of(1, 2, 3);
byte[] bytes = toPrimitiveArray(list, byte[].class); // throws
必要に応じて、そのコードを使用して複製を簡単にすることもできます。
public static int[] toIntArray(List<Integer> list) {
return toPrimitiveArray(list, int[].class);
}
public static double[] toDoubleArray(List<Double> list) {
return toPrimitiveArray(list, double[].class);
}
...
(ただし、そのような複数のメソッドを持つことは、実際には一般的ではありません。)
ときどき目にする解決策の 1 つは、次のようなものです。
public static <P> P toPrimitiveArray(List<?> list) {
Object obj0 = list.get(0);
Class<?> type;
// "unbox" the Class of obj0
if (obj0 instanceof Integer)
type = int.class;
else if (obj0 instanceof Double)
type = double.class;
else if (...)
type = ...;
else
throw new IllegalArgumentException();
Object array = Array.newInstance(type, list.size());
for (int i = 0; i < list.size(); i++) {
Array.set(array, i, list.get(i));
}
return (P) array;
}
ただし、それにはさまざまな問題があります。
Class
引数としてa を渡すだけの方がはるかに優れています。
また、配列をボックス化解除する多くのオーバーロードを記述することも可能ですが:
public static int[] unbox(Integer[] arr) {...}
public static long[] unbox(Long[] arr) {...}
public static double[] unbox(Double[] arr) {...}
...
タイプeraserの影響によりList
、次のように、さまざまなタイプの をボックス化解除するオーバーロードを記述することはできません。
public static int[] unbox(List<Integer> list) {...}
public static long[] unbox(List<Long> list) {...}
public static double[] unbox(List<Double> list) {...}
...
同じ名前と消去を持つ同じクラスに複数のメソッドを持つことは許可されていないため、これはコンパイルされません。メソッドには異なる名前を付ける必要があります。
補足として、一般的ではない解決策を次に示します。
Java 8 の時点で、APIを使用してList
の をボックス化解除できます。Integer
Long
Double
Stream
List<Long> list = List.of(1L, 2L, 3L);
long[] longs = list.stream().mapToLong(Long::longValue).toArray();
Google Guavaのクラスには、次のようなボックス化Collection
解除メソッドがあります。com.google.common.primitives
Doubles.toArray
List<Double> list = List.of(1.0, 2.0, 3.0);
double[] doubles = Doubles.toArray(list);