Java 6とJava 7の自動ボックス化解除の違い


107

Java SE 6とJava SE 7の自動ボックス化解除動作の違いに気付きました。なぜかと思います。これら2つのバージョン間でのこの動作の変更に関するドキュメントが見つからないためです。

以下に簡単な例を示します。

Object[] objs = new Object[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

これは、Java SE 7のjavacで正常にコンパイルされます。ただし、コンパイラに「-source 1.6」引数を指定すると、最後の行でエラーが発生します。

inconvertible types
found   : java.lang.Object
required: int

Java SE 6をダウンロードして、ネイティブバージョン6コンパイラー(-sourceオプションなし)でコンパイルしてみました。それは同意し、上記と同じエラーを出します。

だから何を与えるのですか?いくつかの実験から、Java 6のボックス化解除では、(コンパイル時に)ボックス化されたタイプの値のみをボックス化解除できるように思われます。たとえば、これは両方のバージョンで機能します。

Integer[] objs = new Integer[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

したがって、Java 6と7の間でボックス化解除機能が強化され、値が適切なボックス化されたタイプであることを(コンパイル時に)認識せずに、1度にオブジェクトタイプをキャストおよびボックス化解除できるようになりました。ただし、Java 7がリリースされたときに書かれたJava言語仕様やブログの投稿を読んで、私はこの点の変更を確認できないので、何が変更され、この「機能」が何と呼ばれるのか疑問に思っています。 ?

ただの好奇心:変更により、「間違った」開封解除をトリガーすることが可能です。

Object[] objs = new Float[2];
objs[0] = new Float(5);
int myInt = (int)objs[0];

これは正常にコンパイルされますが、実行時にClassCastExceptionが発生します。

これに関する参照はありますか?


17
面白い。オートボクシングの混乱の新しい成分。あなたの例は、配列の代わりに単一のオブジェクトを使用すると、より単純で明確になると思います。Integer obj = new Integer(2); int x = (int)obj;:Java 7で動作し、Java 6でエラーが発生します
leonbloy 2013

1
どのJDKを使用していますか?それはまた、さまざまなベンダーと関係があるかもしれません...
barfuin

1
@leonbloy:簡略化の良い点は、(元のコードから)多少簡略化しましたが、どういうわけか早く停止しました!
Morty、

@Thomas:私が使用したのは、Oracleの最新のJDK(バージョンごと)でした。
モーティ

2
オートボクシングを使用しないもう1つの理由。
gyorgyabraham 2013

回答:


92

セクション5.5の言語がJava 7 JLSのキャスト変換がJava 5/6 JLSの同じセクションと比較し更新されたようですおそらく許可されている変換を明確にするためたようです。

Java 7 JLSは言う

参照型の式は、ボックス化解除変換によって、エラーなしでプリミティブ型へのキャスト変換を受けることができます。

Java 5/6:

参照型の値は、ボックス化解除変換(§5.1.8)によってプリミティブ型にキャストできます。

Java 7 JLSには、参照型からプリミティブへの許可された変換(このテーブルはJava 5/6 JLSには含まれていません)のテーブル(表5.1)も含まれています。これは、ボックス化解除によるナローイング参照変換として、オブジェクトからプリミティブへのキャストを明示的にリストします。

理由はこのメールで説明されています

結論:仕様の場合。(Object)(int)を許可します(int)(Object)も許可する必要があります。


35

あなたが正しいです; もっと簡単に言うと:

Object o = new Integer(1234);
int x = (int) o;

これはJava 7では機能しますが、Java 6以下ではコンパイルエラーが発生します。奇妙なことに、この機能は目立つように文書化されていません。たとえば、ここでは言及されていません。それが新機能であるかバグ修正であるか(または新しいバグであるか)は議論の余地があります。いくつかの関連情報とディスカッションを参照してください。コンセンサスは、元の仕様のあいまいさを示しているようで、Java 5/6での実装がわずかに不正確で一貫性がなく、JSR 292(動的型付き言語)の実装にとって重要だったため、7で修正されました。

Javaオートボクシングには、さらに多くのトラップとサプライズがあります。例えば

Object obj = new Integer(1234);
long x = (long)obj;

コンパイルさClassCastExceptionれますが、実行時に(で)失敗します。これは代わりに機能します:

long x = (long)(int)obj;


2
答えてくれてありがとう。ただし、わからないことが1つあります。これはJLSとそれに付随する実装(メールディスカッションを参照)の明確化ですが、JVMで他の型付き言語に対応するためになぜそれが行われるのですか?結局のところ、これはVMではなく言語の変更です。VMのキャスト動作は通常どおり機能します。コンパイラは、Integerにキャストして.intValue()を呼び出す既存のメカニズムを使用してこの機能を実装します。では、このJava言語の適切な変更はどのようにしてVMで他の言語を実行するのに役立つのでしょうか。あなたのリンクがこれを示唆していることに同意します。
Morty、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.