質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.36%

  • Java

    14362questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

int[]からInteger[]へのキャストができない理由

解決済

回答 7

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 3,482

zoemond

score 28

知りたいこと

intからIntegerへのキャストはできるのに、int[]からInteger[]へのキャストができません。
Integerはintをオブジェクトとして扱うためにあるものならば、配列のキャストができた方がいいし、言語としても整合性がある気がしてしまいます。

どうしてそのような仕様にしたのでしょうか。
なにが不都合なのでしょうか。

調べたこと①

Integer[]は値オブジェクトへの参照で、int[]はプリミティブの値なのでそもそも違うもの同士はキャストできないという理由は調べました。
なぜそうしたのかが知りたいです。
Integerはintをオブジェクトとして扱うためにオートボクシングしてくれる機能を付けたのに、配列は変換しないようにしたということが納得できません。

調べたこと②

後方互換性、処理効率という話も少し出てきました。

後方互換性については具体的に何がだめなのかイメージできません。

処理効率にいては、int[]からInteger[]へ変換するときは結局ひとつひとつintの値をIntegerに入れるのだから、あらかじめ変換の機能を付けてもらった方がいいと考えてしまいます。

追記:私の理解(間違っている可能性あり)

プリミティブ型:スタック領域に値を保持している
参照型:ヒープ領域に値があり、スタック領域から参照する
参照:値やオブジェクトを指す番号
配列:メモリ領域に連続して要素が並んでいる。a[0]の参照が分かればa[1]は次の参照にある。参照型。
ラッパークラス:プリミティブ型をオブジェクトとして扱えるようにする。参照型。

プリミティブ型→ラッパークラス//OK・・・・①
プリミティブ型の配列→ラッパークラスの配列//できない・・・②

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 7

+3

配列の要素に使っている型同士に継承関係があるなら、配列を別の型の配列に代入することはできます。
しかし、これはあくまで「この配列、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 15:09 編集

    int→Integerの変換ができてint[]→Integer[]の変換ができないというのは整合性がないように見えるという質問に対して、参照の代入を表す=の整合性を保つためという説明でかなり分かりそうだったのですが、少しだけもやもやがあります。

    用語やイメージがあっているのか自信がないのですが、
    intの値がある領域の参照をIntegerに代入できる(オートボクシングではオブジェクトを要求されている所にint値が渡ると自動でオブジェクトに変換させて事なきを得ている)なら
    int[]の値が並んでいる領域の一番初めの参照もInteger[]に代入できる(intの配列にIntegerを入れることができる)のではないでしょうか。
    どうなのでしょうか。

    補足のようなものを質問欄に追記しました。

    追記・補足:新たに配列を作らなければいけないというところがわかりません。すみません。

    キャンセル

  • 2016/05/13 01:23

    そもそも「配列」とは、その型の変数を複数個まとめ、番号でその変数を識別できるようにしている仕組みです。
    intの配列はint型の変数を、Integerの配列はIntegerの変数をまとめて扱っています。そしてそれぞれの配列としての変数は、その配列がある場所を記憶します。

    intはプリミティブ型です。値そのものをその変数が記憶します。
    Integerは参照型です。そのオブジェクトが存在する場所を変数が記憶します。

    intの配列の変数をIntegerの配列の変数に入れようとしたとしましょう。参照の代入なので、それぞれが「同じintの配列」のある場所を記憶する必要があります。
    しかし、Integer配列の変数に渡された場所にあったのはintの配列です。Integerの配列は、この「値そのもの」という要素をIntegerとして扱うことはできません。
    それならばと、各要素をオートボクシングでIntegerに変換したとしましょう。変換はできるでしょう。しかし、Integerの配列としては配列の要素としてIntegerを持っていなければなりません。変換した要素を配列に入れようとする際、配列の実体はintの配列なので、Integerを入れることはできません。

    このようにintの配列とIntegerの配列とでは性質が全く異なるため、intの配列をIntegerの配列として扱うのは無理なのです。

    「じゃあプリミティブの配列のまま、読み込むときにオートボクシングで変換すればいいじゃないか」?ただの配列にそんな芸当はできません。配列はあくまで、ただの変数の集まりなのですから。

    キャンセル

  • 2016/05/16 12:56 編集

    なぜint→Integerは中身が違うのに許されているのか、配列だとなぜだめなのかが疑問点でしたが、いろんな方の回答から自己解決しました。
    丁寧に回答していただきましてありがとうございました。

    キャンセル

+1

簡単に言うと、これが出来ないからです。

Integer[] array1 = new Integer[]{1,2,null,4};// これはOK
int[] array2 = new int[]{1,2,null,4};// これはNG

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/12 11:22 編集

    Integer[]=int[];
    ができないのはなぜですか?
    回答していただいたのにすぐ理解できずに申し訳ないです。
    nullのないint[]からInteger[]への変換はできるような気がしてしまいます。

    キャンセル

  • 2016/05/12 11:48

    Integer[]→int[]変換が出来ないのに、
    int[]→Integer[]変換が出来るようにしてしまうと、
    それこそ整合性が取れていないということになってしまわないでしょうか?

    まぁ、結論的に言ってしまえば、
    Javaではそういう仕様だから出来ない、
    で最終的に理解してもらうしかないと思いますね。

    キャンセル

  • 2016/05/12 14:39

    int とlongのような関係を考えれば、変換が一方通行であるということはそこまで整合性がないということにはならないと感じます。

    Javaの仕様としてできることできないことがあることは分かるのですが、なぜそのような機能にしたのかということが知りたいです。

    質問に答えていただいてありがとうございます。

    キャンセル

+1

配列を配列にキャストする場合、要素同士がキャストできればキャスト可能となっています。

ところが、intIntegerの変換はオートボクシングという別なメカニズムによるもので、キャストはできません(オートボクシング自体があとからJavaへ追加されたこともあって、キャストとは別枠になっています)。

ということで、「要素同士のキャストができない」intIntegerの組み合わせでは、配列もキャストできません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/12 11:27 編集

    回答ありがとうございます。

    キャストという言葉を正しく使えていませんでした。
    int→Integerの変換をつけて、int[]→Integer[]へのオートボクシング機能を付けなかったのはなぜでしょうか。

    キャンセル

+1

なぜそのような仕様にしたのかは仕様策定された方々に聞く内容ではないかと思いますが、一発で変換する方法としては、Commons-LangのArrayUtilsを使えば、プリミティブ配列←→ラッパー配列の変換は可能です。
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/ArrayUtils.html

toArrayやtoPrimitiveメソッドで変換します。

ただし配列の内容によっては実行時例外になります。

あくまで予想ですが、型の変換についてはコンパイラレベルでエラーの有無を判定すべき、という判断があったのではないかと。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/12 17:30 編集

    Commons-Langはすごいですね。使います。

    このような仕様にした理由の正解は作った人しか分かりませんが、もっともらしい理由なら予想できるのではないかなと思いました。

    型の安全性をどこで妥協するかを考えると、プリミティブ配列→ラッパー配列は許してもいいのではと思いました。(Commons-LangでいうtoOblectメソッドです)
    システムを作ったことは1回もありませんが、ジェネリクスクラスの引数にプリミティブ配列を入れたい事とか結構ありそうだと予想したりして、なぜこのような仕様にしたのかが気になりました。

    キャンセル

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 17:18

    ありがとうございます。

    int in = 0;
    long lo = 0;
    in = lo;//コンパイルエラー
    lo = in;//OK

    ということは、片方だけのキャストができると考えているのですがどうでしょうか。
    この通りの整合性で行くと、キャストが一方通行でもいいのでは・・・と感じるのですが・・・

    キャンセル

  • 2016/05/12 18:11

    例えば
    int[] a = new int[5];
    int[] b = a;
    な関係を考えた時、bはaを指しているので実体としては「同じもの」ですよね?
    (b[1]を変更すればa[1]を変更したのと同じことになる)
    仮に
    Integer[] c = a;
    が可能だとするなら、c は a と同じものを指している理屈になりますよね?
    でもInteger[] はIntegerというオブジェクトの配列であってintの配列ではないためInteger[]の中には元のint[]の中に入っていたint値自身とは別の(そのint値を持っている)Integerオブジェクトを生成して配列にした物…でなくてはならない理屈になりますよね?
    となると元のaという配列とはまるっきり別の配列という事になるのでint[]同士の参照(代入)とは扱いを同一視できなくなってしまいます。
    整合性が取れないというのはそういう点も考慮しての事では無いでしょうか。

    キャンセル

  • 2016/05/16 12:58

    なぜint→Integerは実体が違うのに許されているが、配列だと許されないことの整合性が疑問でしたが、自分なりに解決しました。
    丁寧に回答していただきましてありがとうございました。

    キャンセル

0

「なぜそんな仕様にしたのか」
という観点から私なりの考えを書いてみます。
int[]⇒Integer[]
だったらそのまま数字を入れればできる。
Integer[]⇒int[]
なら、できるときはして、できないnullがあったらエラーでも出して・・・
という考え方で仕様にすれば良いということですよね。

おそらくそんな仕様にしてくれれば「プログラムを書く人間からすれば素晴らしく楽なこととなるのに」といったところでしょうか?

では、そのような世界でどのようなことが行われるかをかんがえてみましょうか。
次のような配列があるとします

int[]     a = new int[3];
Integer[] b = new Integer[3];


まあ、この時点でaの中身は{0,0,0}、bの中身は{null,null,null}ですね。
この違いは許容しましょう。

a=b;


これはエラーを出しましょう。

b=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]);
}


を自動でやってくれます。

ところで次のコードを考えてみましょう。

List<Integer> list;
.........
int[] a=new int[3];
for(int i=0;i<999;i++){
   a[0]=i;
   a[1]=i*2;
   a[2]=a[0]+a[1];
   Collections.addAll(list,a[0],a[1],a[2]);
}


aがInteger配列ではない理由はループ内で計算をするためです。
int[]⇒Integer[]が可能であれば

int[] a=new int[3];
for(int i=0;i<999;i++){
   a[0]=i;
   a[1]=i*2;
   a[2]=a[0]+a[1];
   Collections.addAll(list,a);
}


でよくなります。

ここで、少し考えてみましょう。
addAllに「配列内の1つずつを入れた場合」と「配列自体を入れた場合」どちらが処理として重いでしょう?
「配列自体を入れた場合」のほうが重くなります。
理由は、実質new Integer[a.length]という処理がループ中に増えるからです。

一つくらいいいじゃない?と思われるかもしれませんが、

Collections.addAll(list2,a);
Collections.addAll(list3,a);
・
・
・


という文がループ内に更にあったとしたら?
処理は多くなりますよね?

私はここにその仕様の理由があると考えています。

ちなみに通常の、オートボクシング、アンボクシングに対してもこのようなループ中に行う場合はそれなりの負荷がかかるので、使いドコロには注意が必要です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

check解決した方法

-3

そもそも、
Subclass → SuperClass //OK
Subclass[] → SuperClass[] //OK
int → Integer //OK
int[] → Integer[] //コンパイルエラー
という整合性のなさが気になるというのが質問した理由ですが
int → long //OK
int[] → long[] //コンパイルエラー
ということを知りませんでした。
このint[] → long[] の関係を考えれば、プリミティブ配列に関してはswordoneさんや HiroshiWatanabeさんの回答の通り、中身の型を一致させなければいけないという理由で、
int[] → Integer[] //コンパイルエラー
ということの整合性はあっていることに気付きました。
そして、どうして配列は中身の型を一致させなければいけない仕様にしたかという点については、インスタンス生成の効率面を考えてのことだというRyotaKondoさんの解釈で納得しました。

いろいろな方に回答をしていただいて、それがまとまって納得したので、自己解決という形にします。

質問の仕方や、質問する側の知識がまとはずれで、回答しづらくしてしまい申し訳ありませんでした。
また、ちょっとめんどくさい疑問だったと思いますが、すぐにいろいろな方に助けていただけたのでびっくりしました。ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • Java

    14362questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。