41436


Javaで以下のようにint型の変数にchar型を代入してもコンパイル・実行できる理由がよくわかりません。  
なぜコンパイルできるのか？また、なぜ出力がこの値になるのか分かる方いませんでしょうか。

[code]

    public class Test {
      public static void main(String[] args) {
    
        int i = 'あ';
    
        System.out.println(i);
      }
    }
    
[/code]

* * *

▼実行結果

[code]

    12354
    
[/code]


CC BY-SA 3.0
2018-02-03T07:06:33.173
41432
2018-02-03T14:05:52.507
27262
question
java
なぜint型にchar型を代入してもコンパイルエラーにならないのか


文字コードが表示されています。  
「あ」の文字コードを10進数で表すと「12345」だからです。


CC BY-SA 3.0
2018-02-03T07:22:41.323
41433
2018-02-03T07:51:11.217
2018-02-03T07:51:11.217
23148
23148
41432
answer


> Javaで以下のようにint型の変数にchar型を代入してもコンパイル・実行できる理由がよくわかりません。

charやintはプリミティブ型と言います。  
~~このプリミティブ型ではビット数の多い型への代入は言語仕様として、暗黙的に変換されるようになっています。~~
(こちらを[参照](https://ja.stackoverflow.com/a/41436/24823)してください。)  
char型のbit数は16, int型のbit数は32となっていますので、 質問にある通りのコードでもコンパイルと実行が可能なわけです。  
逆に、int型からchar型へはbit数がすくなるなるので、明示的なキャストが必須になります。

> また、なぜ出力がこの値になるのか分かる方いませんでしょうか。

'あ'はUnicodeで10進数の12354に相当します。


CC BY-SA 3.0
2018-02-03T08:06:39.517
41434
2018-02-03T14:05:52.507
2018-02-03T14:05:52.507
24823
24823
41432
answer


ニュアンスとしては、表現力の小さい型から、(それを包含する)表現力の大きい型へ変換する場合には問題が発生する要素がないので、特別な手続きなしに暗黙的に変換してくれる、という考え方になります。

今回の件で言うと、`'あ'`は`char`型、`i`は`int`型です。  
`char`で表現できる数値は全て`int`も表現可能なのでプログラマに意識させずにJavaが変換してくれています。

`あ`のUTF-16コードは次のPDFに記載されている通り16進数で`3042`ですが、これを10進数に直すと`12354`となります。

  * <http://www.unicode.org/charts/PDF/U3040.pdf>

* * *

仕様を参照して説明すると:

`'あ'`は文字リテラルです。これはJavaでは`char`型になります([3.10.4. Character
Literals](https://docs.oracle.com/javase/specs/jls/se9/html/jls-3.html#jls-3.10.4))。

`char`から`int`の型変換は **widening primitive conversions** ([5.1.2. Widening
Primitive
Conversion](https://docs.oracle.com/javase/specs/jls/se9/html/jls-5.html#jls-5.1.2))です。

そして、代入時には右辺の式の型を左辺の変数の型に変換する必要があります([5.2. Assignment
Contexts](https://docs.oracle.com/javase/specs/jls/se9/html/jls-5.html#jls-5.2))が、ここでは上記のwidening
primitive conversionが許容されています。

したがって、

> int i = 'あ';

はJavaとして妥当で、前述の[5.1.2節](https://docs.oracle.com/javase/specs/jls/se9/html/jls-5.html#jls-5.1.2)の通り精度を保ったまま`char`から`int`へ変換されます。

* * *

[Daichi
Itokazuさんの回答](https://ja.stackoverflow.com/a/41434/2808)は、若干正確さを欠いています。

> このプリミティブ型ではビット数の多い型への代入は言語仕様として、暗黙的に変換されるようになっています。

`float`は32ビット、`long`は64ビットのプリミティブ型ですが([Primitive Data
Types](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html))、`float`から`long`は[narrowing変換](https://docs.oracle.com/javase/specs/jls/se9/html/jls-5.html#jls-5.1.3)であり、代入時の変換として許されていません。([明示的なキャスト](https://docs.oracle.com/javase/specs/jls/se9/html/jls-5.html#jls-5.5)が必要)(浮動小数と整数)。

また、`byte`は8ビット、`char`は16ビットのプリミティブ型ですが、`byte`から`char`の変換は[widening and
narrowing primitive
conversion](https://docs.oracle.com/javase/specs/jls/se9/html/jls-5.html#jls-5.1.4)であり、これも代入時に許されている変換ではありません(いわゆる`signed`と`unsigned`)。

* * *

版は少し古いようですが、JLSを和訳されている方がいらっしゃいましたので付記します。

  * [Java言語規定 変換及び昇格](http://www.y-adagio.com/public/standards/tr_javalang/5.doc.htm)


CC BY-SA 3.0
2018-02-03T11:48:04.363
41436
2018-02-03T11:48:04.363
2808
41432
answer