###知りたいこと
intからIntegerへのキャストはできるのに、int[]からInteger[]へのキャストができません。
Integerはintをオブジェクトとして扱うためにあるものならば、配列のキャストができた方がいいし、言語としても整合性がある気がしてしまいます。
どうしてそのような仕様にしたのでしょうか。
なにが不都合なのでしょうか。
###調べたこと①
Integer[]は値オブジェクトへの参照で、int[]はプリミティブの値なのでそもそも違うもの同士はキャストできないという理由は調べました。
なぜそうしたのかが知りたいです。
Integerはintをオブジェクトとして扱うためにオートボクシングしてくれる機能を付けたのに、配列は変換しないようにしたということが納得できません。
###調べたこと②
後方互換性、処理効率という話も少し出てきました。
後方互換性については具体的に何がだめなのかイメージできません。
処理効率にいては、int[]からInteger[]へ変換するときは結局ひとつひとつintの値をIntegerに入れるのだから、あらかじめ変換の機能を付けてもらった方がいいと考えてしまいます。
###追記:私の理解(間違っている可能性あり)
プリミティブ型:スタック領域に値を保持している
参照型:ヒープ領域に値があり、スタック領域から参照する
参照:値やオブジェクトを指す番号
配列:メモリ領域に連続して要素が並んでいる。a[0]の参照が分かればa[1]は次の参照にある。参照型。
ラッパークラス:プリミティブ型をオブジェクトとして扱えるようにする。参照型。
プリミティブ型→ラッパークラス//OK・・・・①
プリミティブ型の配列→ラッパークラスの配列//できない・・・②
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答7件
0
配列の要素に使っている型同士に継承関係があるなら、配列を別の型の配列に代入することはできます。
しかし、これはあくまで「この配列、A型が入っているんだからその親クラスのB型としても使えるね」という理由で入れているに過ぎません。(蛇足ですが、これはタイプセーフではなくなり、Javaの失敗とも言われている→参考:Java配列メモ | 共変)
int配列は仰るとおりプリミティブの値が入っており、このままではIntegerというオブジェクトとして扱うことはできません。オートボクシングではオブジェクトを要求されている所にint値が渡ると自動でオブジェクトに変換させて事なきを得ているのですが、intの配列に入っているint値をIntegerに変換しても、**intの配列にIntegerを入れることができません。**そのため、別個にIntegerの配列を新たに作成する必要が生まれます。
しかし、そもそものことを思い出して欲しいのですが、オブジェクトに対して"="は参照の代入を意味します。ということは、参照の代入をして2つの配列変数は同じ配列オブジェクトを指すはずなのに、違う配列を作成して別のオブジェクトを作成しなければならないというのは整合性が取れません。そもそもただの代入で新たに配列を作成するほどJavaはおせっかいではありません。
同じ理由で、Integer配列をint配列に変換させようとしてIntegerをアンボクシングしてintにしても、Integerというオブジェクトを扱う配列にint値を置くことができないため、変換できません。
以上の理由で、int配列⇔Integer配列の変換は認められていないのだと思います。
投稿2016/05/12 02:26
編集2016/05/12 02:38総合スコア20651
0
なぜそのような仕様にしたのかは仕様策定された方々に聞く内容ではないかと思いますが、一発で変換する方法としては、Commons-LangのArrayUtilsを使えば、プリミティブ配列←→ラッパー配列の変換は可能です。
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/ArrayUtils.html
toArrayやtoPrimitiveメソッドで変換します。
ただし配列の内容によっては実行時例外になります。
あくまで予想ですが、型の変換についてはコンパイラレベルでエラーの有無を判定すべき、という判断があったのではないかと。
投稿2016/05/12 07:39
総合スコア12011
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
配列を配列にキャストする場合、要素同士がキャストできればキャスト可能となっています。
ところが、int
⇔Integer
の変換はオートボクシングという別なメカニズムによるもので、キャストはできません(オートボクシング自体があとからJavaへ追加されたこともあって、キャストとは別枠になっています)。
ということで、「要素同士のキャストができない」int
⇔Integer
の組み合わせでは、配列もキャストできません。
投稿2016/05/12 02:03
総合スコア145184
0
簡単に言うと、これが出来ないからです。
Java
1Integer[] array1 = new Integer[]{1,2,null,4};// これはOK 2int[] array2 = new int[]{1,2,null,4};// これはNG
投稿2016/05/12 02:02
総合スコア1280
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/12 02:24 編集
2016/05/12 02:48
2016/05/12 05:39
0
自己解決
そもそも、
Subclass → SuperClass //OK
Subclass[] → SuperClass[] //OK
int → Integer //OK
int[] → Integer[] //コンパイルエラー
という整合性のなさが気になるというのが質問した理由ですが
int → long //OK
int[] → long[] //コンパイルエラー
ということを知りませんでした。
このint[] → long[] の関係を考えれば、プリミティブ配列に関してはswordoneさんや HiroshiWatanabeさんの回答の通り、中身の型を一致させなければいけないという理由で、
int[] → Integer[] //コンパイルエラー
ということの整合性はあっていることに気付きました。
そして、どうして配列は中身の型を一致させなければいけない仕様にしたかという点については、インスタンス生成の効率面を考えてのことだというRyotaKondoさんの解釈で納得しました。
いろいろな方に回答をしていただいて、それがまとまって納得したので、自己解決という形にします。
質問の仕方や、質問する側の知識がまとはずれで、回答しづらくしてしまい申し訳ありませんでした。
また、ちょっとめんどくさい疑問だったと思いますが、すぐにいろいろな方に助けていただけたのでびっくりしました。ありがとうございました。
投稿2016/05/16 03:54
総合スコア50
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
「なぜそんな仕様にしたのか」
という観点から私なりの考えを書いてみます。
int[]⇒Integer[]
だったらそのまま数字を入れればできる。
Integer[]⇒int[]
なら、できるときはして、できないnullがあったらエラーでも出して・・・
という考え方で仕様にすれば良いということですよね。
おそらくそんな仕様にしてくれれば「プログラムを書く人間からすれば素晴らしく楽なこととなるのに」といったところでしょうか?
では、そのような世界でどのようなことが行われるかをかんがえてみましょうか。
次のような配列があるとします
java
1int[] a = new int[3]; 2Integer[] b = new Integer[3];
まあ、この時点でaの中身は{0,0,0}、bの中身は{null,null,null}ですね。
この違いは許容しましょう。
java
1a=b;
これはエラーを出しましょう。
java
1b=a;
これは・・・プログラムとしては
Integer[]を作成。aの各数字をオートボクシングして作成です。
つまり、事実上
b=new Integer[a.length]; for(int i=0;i<a.length;i++){ b[i]=Integer.valueOf(a[i]); //又はb[i]=new Integer(a[i]); }
を自動でやってくれます。
ところで次のコードを考えてみましょう。
java
1List<Integer> list; 2......... 3int[] a=new int[3]; 4for(int i=0;i<999;i++){ 5 a[0]=i; 6 a[1]=i*2; 7 a[2]=a[0]+a[1]; 8 Collections.addAll(list,a[0],a[1],a[2]); 9} 10
aがInteger配列ではない理由はループ内で計算をするためです。
int[]⇒Integer[]が可能であれば
java
1int[] a=new int[3]; 2for(int i=0;i<999;i++){ 3 a[0]=i; 4 a[1]=i*2; 5 a[2]=a[0]+a[1]; 6 Collections.addAll(list,a); 7} 8
でよくなります。
ここで、少し考えてみましょう。
addAllに「配列内の1つずつを入れた場合」と「配列自体を入れた場合」どちらが処理として重いでしょう?
「配列自体を入れた場合」のほうが重くなります。
理由は、実質new Integer[a.length]という処理がループ中に増えるからです。
一つくらいいいじゃない?と思われるかもしれませんが、
java
1Collections.addAll(list2,a); 2Collections.addAll(list3,a); 3・ 4・ 5・
という文がループ内に更にあったとしたら?
処理は多くなりますよね?
私はここにその仕様の理由があると考えています。
ちなみに通常の、オートボクシング、アンボクシングに対してもこのようなループ中に行う場合はそれなりの負荷がかかるので、使いドコロには注意が必要です。
投稿2016/05/13 18:33
総合スコア94
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
気にしたこと無かった&私も知らなかったので今回の回答で一緒に勉強させてもらっています。
まとめるとこういう事でしょうか…?
Q1.int→Integerができるのにint[]→Integer[]ができないのは何故か?(int→Integerのオートボクシング)
A1.int[]→Integer[]ができないのはInteger[]→int[]ができないから片方(逆向き)だけできると整合性が取れないため
Q2.Integer→intができるのにInteger[]→int[]ができないのは何故か?(Integer→intのアンボクシング)
A2.Integer→intのアンボクシングができるのはIntegerがnullでない事が前提
(nullなIntegerをintにしようとすればNullPointerExceptionが発生する)
つまりInteger→intはIntegerがnullでない時に限定してのみintにできる
Integer[]→int[]の場合は配列の中身にnullが入っている可能性があるのでint[]にできる保証が無い=できない
投稿2016/05/12 08:10
総合スコア2160
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/12 08:18
2016/05/12 09:11
2016/05/16 03:58
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/12 09:18 編集
2016/05/12 16:23
2016/05/16 03:59 編集