Javaの型キャストメカニズムは、プログラマーが一つの型の値を別の型に明示的または暗黙的に変換することを可能にします。この機能は歴史的にCおよびC++から受け継がれましたが、Javaでは型安全性を高めるために制限されています。これにより、オーバーフローやデータ喪失に関連する隠れたバグを防ぐことができます。
問題としては、リファレンスタイプのキャストでClassCastExceptionが発生する可能性があることや、プリミティブタイプのキャストで精度が失われること(例えば、doubleからintへの変換など)が挙げられます。"ダウンキャスティング"(サブタイプへのキャスト)の場合、インスタンスがそのクラスに属さないと論理的なエラーが発生する可能性があります。
解決策は、厳密に分けることです:
プリミティブに関するコード例:
int i = 100; long l = i; // 暗黙的キャスト (int -> long) double d = l; // 暗黙的 (long -> double) int i2 = (int) d; // 明示的キャスト (小数部分の喪失)
リファレンスタイプに関するコード例:
Object obj = "Hello"; // アップキャスティング、暗黙的 String s = (String) obj; // ダウンキャスティング、明示的
主な特徴:
Javaコンパイラは間違った型キャストをすべて防げますか?
回答:いいえ、コンパイラはコンパイル時に明らかなエラーのみを検出します。型の構造内でキャストが可能であっても(例:Object -> String)、変数が実際に互換性のないタイプのオブジェクトを参照している場合、エラーは実行時にClassCastExceptionとして現れます。
IntegerはLongを継承しており、Integer i = (Integer) someLongと書けますか?
回答:いいえ、IntegerとLongは独立したラッパークラスであり、間でダウンキャスティングを行うことはできません。両者はNumberから継承していますが、互いには継承していません。(Integer) (Object) 1L;のようなキャストはClassCastExceptionを引き起こします。
floatをintに明示的キャストする際、小数部分は四捨五入されますか?
回答:いいえ、小数部分は切り捨てられ、四捨五入されることはありません:
float f = 3.99f; int i = (int) f; // i == 3, 4ではない
開発者はObjectのコレクションを受け取り、各要素を自分の型にキャストしますが、instanceofを確認しません。プロジェクトは不正なデータでClassCastExceptionにより安定してクラッシュします。
利点:
欠点:
すべてのダウンキャスティング操作はif (obj instanceof TargetType)内で行われ、エラーハンドリングが明示的です。コレクションにはジェネリクスが適用されます。
利点:
欠点: