web-dev-qa-db-ja.com

Arrays.asList()が正常に機能していませんか?

Float []があり、同じ要素のリストを取得したいと考えています。私はそれらを1つずつ追加するという醜いことを行うことができましたが、Arrays.asListメソッドを使用したいと思いました。しかし問題があります。これは機能します:

List<Integer> list = Arrays.asList(1,2,3,4,5);

しかし、これはそうではありません。

int[] ints = new int[] {1,2,3,4,5};
List<Integer> list = Arrays.asList(ints);

AsListメソッドはvarargsパラメータを受け入れますが、これは私の知識の拡張として、配列の「省略形」です。

質問:

  • 2番目のコードがList<int[]>を返すのにList<int>を返さないのはなぜですか。

  • それを修正する方法はありますか?

  • ここでオートボクシングが機能しないのはなぜですか。つまり、int[]からInteger[]

49

これはどう?

Integer[] ints = new Integer[] {1,2,3,4,5};
List<Integer> list = Arrays.asList(ints);
26
JRL

Java-ジェネリックはプリミティブをサポートしていません。)にList<int>のようなものはありません。

オートボクシングは、プリミティブのarraysではなく、単一の要素に対してのみ発生します。

それを修正する方法については-このようなことをするためのたくさんの方法を持つさまざまなライブラリがあります。これを回避する方法はありません。JDK内で簡単にするための方法はありません考えません。一部はラッパータイプのリストにプリミティブ配列をwrapし(アクセス時にボクシングが発生するようにします)、他は元の配列を反復して作成します彼らが行くように独立したコピー、ボクシング。どちらを使用しているかを確認してください。

(編集:私はint[]の開始点は交渉不可能であると想定していました。Integer[]で始めることができれば、それで十分です:)

ヘルパーライブラリの1つの例として、 Guava をプラグインするために com.google.common.primitive.Ints.asList があります。

69
Jon Skeet

Java配列はオブジェクトであり、Arrays.asList()はint配列をvarargsリストのsingle引数として扱うためです。

13
ChssPly76

Java 8と入力します。ボックス化された配列に収集するには、次のようにします。

_Integer[] boxedInts = IntStream.of(ints).boxed().toArray(Integer[]::new);
_

または、これをボックス化されたリストに収集します

_List<Integer> boxedInts = IntStream.of(ints).boxed().collect(Collectors.toList());
_

ただし、これは_int[]_、_long[]_、および_double[]_に対してのみ機能します。これは_byte[]_では機能しません。

Arrays.stream(ints)IntStream.of(ints)は同等であることに注意してください。したがって、前の2つの例は次のように書き換えることもできます。

_Integer[] boxedIntArray = Arrays.stream(ints).boxed().toArray(Integer[]::new);
List<Integer> boxedIntList = Arrays.stream(ints).boxed().collect(Collectors.toList());
_

この最後の形式は、Streamのプリミティブ固有のサブタイプを省略しているため、好まれます。ただし、内部的にはまだオーバーロードされたものであり、この場合は内部でIntStreamを作成します。

12
YoYo

問題はArrays.asList()ではありません。問題は、配列に対してオートボクシングが機能することを期待していることです-機能しません。最初のケースでは、コンパイラーは個々のintを、それが何に使用されているかを調べる前にオートボックス化します。 2番目のケースでは、最初にそれらをint配列に入れ(オートボクシングは不要)、それをArrays.asList()に渡します(オートボクシングは不可)。

4

ここでオートボクシングが機能しないのはなぜですか。つまり、int []からInteger []へ?

オートボクシングはintIntegerに変換しますが、_int[]_を_Integer[]_に変換しません。

何故なの?

簡単な(しかし満足できない)答えは、それがJLSが言うことだからです。 (必要に応じて確認できます。)

本当の答えは、オートボクシングが何をしているか、そしてなぜそれが安全であるかについての基礎です。

コードのどこかに_1_をオートボックスすると、同じIntegerオブジェクトが取得されます。これは、すべてのint値には当てはまりません(Integerオートボクシングキャッシュのサイズが制限されているため)。ただし、equalsを使用してIntegerオブジェクトを比較すると、 「正しい」答えが得られます。

基本的に_N == N_は常にtrueであり、new Integer(N).equals(new Integer(N))は常にtrueです。さらに、これら2つのことremain true ... Pure Javaコードを使用することを前提としています。

これを検討してください:

_int[] x = new int[]{1};
int[] y = new int[]{1};
_

これらは等しいですか?番号! _x == y_はfalseで、x.equals(y)はfalseです!しかし、なぜ?なぜなら:

_y[0] = 2;
_

言い換えると、Java配列は変更可能であるため、同じタイプ、サイズ、内容の2つの配列は常に区別できます。

オートボクシングの「約束」は、結果が区別できないため、実行しても問題ないということです1。ただし、配列のequalsの定義と配列の可変性により、すべての配列は根本的に区別できるためです。したがって、プリミティブ型の配列のオートボクシングwasが許可されると、「約束」が損なわれます。


1-.....自動ボックス化された値が等しいかどうかをテストするために_==_を使用しない場合。

2
Stephen C

Arrays.asList(T... a)は、実際のオブジェクト(Objectのサブクラス)の配列と一致する_T[]_を配列として効果的に受け取ります。プリミティブ型はObjectから派生しないため、このように一致しないのはプリミティブの配列だけです。したがって、_int[]_は_Object[]_ではありません。

次に起こるのは、varagsメカニズムが起動し、1つのオブジェクトを渡したかのように扱い、そのタイプの1つの要素配列を作成することです。したがって、_int[][]_(ここで、Tは_int[]_)を渡し、最終的に1要素の_List<int[]>_が必要になります。

ただし、かなり良いオプションがいくつかあります。

グアバのInt.asList(int[])アダプター

プロジェクトで既にグアバを使用している場合は、グアバが提供するアダプターを使用するのと同じくらい簡単です: Int.asList() 。関連するクラスの各プリミティブ型に同様のアダプタがあります。たとえば、Booleansの場合はbooleanなどです。

_int foo[] = {1,2,3,4,5};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
    System.out.println(i);
}
_

このアプローチの利点は、既存の配列の周りに薄いラッパーを作成するため、ラッパーの作成は一定の時間であり(配列のサイズに依存しない)、必要なストレージはわずかな一定量(基になる整数配列に加えて、100バイト未満)。

欠点は、各要素にアクセスするには、基になるintのボックス化操作が必要であり、設定にはボックス化解除が必要なことです。リストに頻繁にアクセスすると、大量の一時的なメモリ割り当てが発生する可能性があります。平均して各オブジェクトに何度もアクセスする場合は、オブジェクトを1回ボックス化してIntegerとして格納する実装を使用することをお勧めします。以下の解決策はそれを行います。

Java 8 IntStream

Java 8では、Arrays.stream(int[])メソッドを使用してint配列をStreamに変換できます。ユースケースによっては、 forEach(IntConsumer) を使用して各要素で何かを行うなど、ストリームを直接使用できる場合があります。その場合、このソリューションは非常に高速であり、ボクシングは発生しませんまたはまったくボックス化解除し、基になる配列のコピーを作成しません。

あるいは、本当に_List<Integer>_が必要な場合は、stream.boxed().collect(Collectors.toList())ここに推奨 として使用できます。そのアプローチの欠点は、リスト内のすべての要素を完全にボックス化することです。これにより、メモリフットプリントがほぼ1桁増加し、ボックス化されたすべての要素を保持する新しい_Object[]_が作成されます。後でリストを頻繁に使用し、Integersではなくintオブジェクトが必要な場合、これは報われることがありますが、注意が必要です。

2
BeeOnRope

_int[]_をArrays.asList()に渡すと、作成されるリストは_List<int[]>_になります。これは、正しい_List<Integer>_ではなく、Javaでは有効ではありません。

私はあなたがArrays.asList()があなたのintを自動ボックス化することを期待していると思います、あなたが見たように、それはしません。

1
Tom Neyland

int[]Integer[]に変換することはできません。値をコピーする必要があります


int[] tab = new int[]{1, 2, 3, 4, 5};
List<Integer> list = ArraysHelper.asList(tab);

public static List<Integer> asList(int[] a) {
    List<Integer> list = new ArrayList<Integer>();
    for (int i = 0; i < a.length && list.add(a[i]); i++);
    return list;
}
1
Maciek Kreft