読み込み中...

初心者もプロも必見!Javaキャストの徹底解説10選

Javaキャスト徹底解説イメージ Java
この記事は約28分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaのキャストは、数値計算、継承関係を持つクラス、コレクションから取り出した値、外部ライブラリの戻り値を扱う場面で判断が必要になります。ただし、すべての型変換をキャストで解決しようとすると、ClassCastExceptionや値の切り捨てにつながるため、変換できる範囲と失敗する条件を先に押さえる必要があります。

そのため、最初の結論は明確です。数値型ではintからdoubleのような拡大変換を優先し、doubleからintのような縮小変換では情報が落ちる前提で書きますし、ここがポイントです。参照型ではinstanceofやパターンマッチングで型を確かめ、Objectから目的の型へ無条件に変換しない書き方が安全です。

Javaの仕様に関する一次情報は、OracleのJava Language Specification 第5章で確認できます。標準APIの詳細はJava SE 21 API Documentationが基準になり、Integer.parseIntNumberFormatExceptionの挙動も公式ページから確認できます。

動作確認環境
  • Java SE 21 / JDK 21
  • Spring Framework 6系を想定したコード例を一部に含みます
  • コマンドライン出力は標準出力 System.out.println を前提にしています
📖 この記事で学べること
  • intdoublelongなど数値型キャストの扱い方
  • ObjectStringIntegerなど参照型変換で失敗しやすい条件
  • instanceoftrycatchを使った安全な型チェック
  • MapHashMapから値を取り出すときのキャスト設計
  • フレームワーク連携時にClassCastExceptionを避ける考え方

関連する基礎を補強したい場合は、Java List型完全ガイドでコレクションの型を確認し、Javaのオーバーライド解説で継承とメソッド解決を整理すると理解しやすくなります。キャストは単独の構文ではなく、型システム、継承、例外処理とつながって動くためです。

Javaとは:プログラミングの世界への第一歩

Javaは静的型付けのプログラミング言語で、変数、メソッド引数、戻り値に型が付きます。この型情報をコンパイル時に確認する仕組みがあるため、Stringを数値として足し算したり、関係のないクラスへ変換したりする誤りを早い段階で見つけやすくなるのが基本です。

その一方で、プログラムの中では型が合わない値を受け取る場面があります。たとえば、Map<String, Object>から値を取り出すと戻り値はObjectになり、文字列として使うにはStringへ変換する判断が必要になります。

Javaの特徴としてよく挙げられるのは、JVM上で動作するプラットフォーム独立性、classを中心にしたオブジェクト指向、不要なメモリを回収するガベージコレクションです。ただし、これらの特徴はキャストと無関係ではなく、参照型を扱う仕組みと深く結び付いているのが目安です。

具体的には、extendsで継承した子クラスを親クラスとして扱えるため、Animal型の変数にDog型のインスタンスを代入できます。この代入はアップキャストと呼ばれ、明示的な構文を書かなくてもコンパイラが許可します。

ただし、親クラスの参照を子クラスへ戻すダウンキャストでは、実体が本当に子クラスかを確認しなければなりません。その確認なしに(Dog)のようなキャストを書くと、実行時にClassCastExceptionが発生する可能性があるのがポイントです。

一般に、Javaが企業システムやWebアプリケーションで使われる理由は、長期運用を想定した型の明確さ、標準APIの広さ、エコシステムの厚さにあります。Springなどのフレームワークを使うと抽象型やObject型を受け渡す場面も増えるため、キャストの理解が保守性に影響します。

この基礎を押さえると、キャストを単なる記号ではなく、Javaの型安全性を保ちながら値を扱うための操作として読めるのが一般的です。型が合っているか、値が失われないか、失敗したときに例外処理へ渡せるかを考える姿勢が軸になります。

Javaの特徴と型の関係

Javaのbyteshortintlongfloatdoublecharbooleanは基本データ型です。これらは値そのものを表すため、参照型であるStringObjectとは扱いが異なります。

一方、IntegerDoubleLongなどはラッパークラスです。基本データ型とラッパークラスの間ではオートボクシングやアンボクシングが働きますが、文字列から数値へ変える処理はInteger.parseIntのような変換メソッドを使いるのが現実的です。

この違いを混同すると、(Integer) "123"のような無効なキャストを書いてしまいます。文字列"123"は数値を表す見た目を持っていても、実体はStringなので、キャストではなく解析処理が必要になります。

キャストとは:データ型の変換術

キャストとは、ある型の値を別の型として扱うための操作です。Javaでは(double) a(Car) vehicleのように、変換先の型名を丸括弧で囲んで式の前に置きますが、これは押さえたい点です。

ただし、キャストができることと、変換後の値が期待どおりになることは別問題です。数値型では範囲や小数部の扱いが問題になり、参照型では実際のインスタンスが変換先クラスのオブジェクトかどうかが問題になります。

具体的には、intからdoubleへの変換は値の範囲が広がるため安全に扱いやすく、Javaは暗黙的な変換を許可します。逆にdoubleからintへ変えると小数部が切り捨てられるため、明示的なキャストを書かせる設計になっていると整理できます。

参照型では、子クラスから親クラスへ変換するアップキャストが自然に成立します。親クラスから子クラスへ戻すダウンキャストは、実体が子クラスである場合に限って成立するため、instanceofによる確認が読みやすい防御になります。

分類主なリスク安全な書き方関連語
拡大数値変換intからlong小さい暗黙変換を使うwidening
拡大数値変換intからdouble精度表現に注意必要なら(double)で意図を示すdouble
縮小数値変換doubleからint小数部の切り捨て丸め処理を先に決めるMath.round
縮小数値変換longからint範囲外の値Math.toIntExactを検討するArithmeticException
文字変換charからint文字コードの理解不足用途をコメントで補うchar
論理値booleanから数値キャスト不可条件式で分岐するtrue
アップキャストCarからVehicle子クラス固有メソッドに触れない親型の契約で扱うextends
ダウンキャストVehicleからCarClassCastExceptioninstanceofで確認するinstanceof
インターフェースListからArrayList実装依存可能ならListのまま扱うList
コレクションObjectからString中身の型違いジェネリクスを使うMap
ジェネリクスList<Object>取り出し時のキャスト増加List<String>へ絞るgenerics
文字列解析Stringからint形式不正Integer.parseIntを使うNumberFormatException
ラッパー変換intからIntegernullの扱いオートボクシングを理解するInteger
アンボクシングIntegerからintNullPointerExceptionnullチェックを入れるnull
配列Object[]からString[]配列の実体不一致要素ごとに確認するArrayStoreException
列挙型Stringからenum未知の値valueOfを例外処理するenum
OptionalOptional<Object>中身の型違いmap内で確認するOptional
StreamStream<Object>途中で例外filterで型を絞るStream
API戻り値Object戻り値呼び出し側依存戻り値型を具体化するreturn
Springサービス戻り値実体の不一致DTO型で返す@RestController
JSON数値の取り出しIntegerLongか不明ライブラリの型仕様を確認するJsonNode
例外処理trycatch握りつぶし原因をログや戻り値に残すcatch
パターンマッチinstanceof String s古い環境で不可JDKバージョンを確認するString s
丸め小数から整数切り捨て誤解BigDecimalを検討するBigDecimal
金融計算doubleの金額二進浮動小数点誤差BigDecimalを使うRoundingMode
比較==equals参照比較の誤用値比較はequalsequals
定数final変数型推論の誤解宣言型を読むfinal
varvar value推論型が見えにくい初期化式から判断するvar
メソッド引数Object value呼び出し側の自由度が高すぎる引数型を狭めるparameter
戻り値設計Objectを返す利用側にキャスト負担型付きDTOを返すrecord

この早見表の要点は、キャストを増やすほど安全になるわけではないという点にあります。型を狭める前に、変数宣言、戻り値、ジェネリクス、DTO設計で型を表現できないかを検討すると、読み手が追うべき条件が少なくなります。

アップキャストとダウンキャスト

アップキャストは、サブクラスのオブジェクトをスーパークラスの型として扱う変換です。DogAnimalの一種である、という継承関係があるため、Animal animal = new Dog();のような代入が成立すると理解できます。

一方、ダウンキャストは逆向きの変換になります。Animal型の参照が常にDogを指すとは限らないため、Dog dog = (Dog) animal;を書く前に実体の確認が必要になります。

その確認にはinstanceofが使えると覚えるとよいでしょう。JDK 21ではif (animal instanceof Dog dog)のような書き方も使えるため、チェックと変数宣言をまとめられます。

💡 Tips: キャストは型変換の構文ですが、設計の不足を隠すための構文ではありません。戻り値や引数を具体的にできる場面では、Objectよりも目的に合う型を使うほうが読みやすくなります。

キャストの詳細な使い方:実用的な知識を手に入れる

Javaのキャスト構文は短いものの、数値型と参照型で判断基準が変わりますし、これが一つの目安です。数値型では値の範囲と精度、参照型では継承関係と実体のクラスを確認するのが出発点になります。

具体的には、数値の拡大変換ではキャストを書かなくても代入できますが、学習段階では(double)のように明示して、どの地点で型が変わるのかを読み取る練習が役立ちます。ただし、本番コードでは冗長なキャストがノイズになる場合もあると考えられます。

基本的なキャストの方法

基本形は、変換したい式の前に(型名)を置く書き方です。intの値をdoubleとして扱う場合は、変数の前に(double)を置き、代入先をdouble型にします。

int a = 5;
double b = (double) a;
System.out.println(b); // 出力結果は 5.0

結果: 期待される出力は5.0です。intの整数値5doubleとして扱われるため、小数部を持つ形式で出力されます。

この変換は拡大変換にあたるため、double b = a;のように書いても成立すると言えるでしょう。そのため、明示的なキャストは必須ではありませんが、学習用コードでは型が変わる地点を示す効果があります。

型変換の注意点

型変換で初心者がつまずきやすいのは、見た目の値と実際の型を同じものとして扱ってしまう点です。"5"は数字に見えますがStringであり、5intリテラルになります。

そのため、文字列から数値へ変える場合はキャストではなく解析を使いるのが基本です。Integer.parseIntLong.parseLongDouble.parseDoubleなどのメソッドは、文字列の形式が不正なときにNumberFormatExceptionを投げます。

一方、数値型同士のキャストではコンパイルが通っても値が変わる場合があります。doubleintへ変えると小数部が丸められるのではなく切り捨てられるため、四捨五入が必要な処理ではMath.roundなどの別手段を検討するのが目安です。

サンプルコード1:数値型のキャストの使い方

数値型の縮小変換では、変換先に収まらない情報が失われる可能性があります。小数点以下の値を持つdoubleintへ変えると、小数部は残りません。

double c = 5.7;
int d = (int) c;
System.out.println(d); // 出力結果は 5

結果: 期待される出力は5です。5.7の小数部.7が切り捨てられ、整数部分だけがintとして残ります。

この挙動を四捨五入と混同しないことが大切になるのがポイントです。四捨五入が目的ならMath.round(c)、金融計算のように丸め規則を明示したいならBigDecimalRoundingModeを検討します。

サンプルコード2:オブジェクト型のキャストの使い方

オブジェクト型のキャストでは、変数の宣言型だけでなく、実際に生成されたインスタンスの型を見ます。Animal animal = new Animal();で作られた実体はDogではないため、Dogへのキャストは失敗するのが一般的です。

class Animal {}
class Dog extends Animal {}

public static void main(String[] args) {
    Animal animal = new Animal();
    Dog dog = (Dog) animal; // ここでClassCastExceptionが発生します
}

結果: 期待される挙動はClassCastExceptionの発生です。animalの実体がDogではないため、(Dog)によるダウンキャストは成立しません。

この失敗を避けるには、if (animal instanceof Dog dog)のように確認してから子クラスの変数を使います。JDKのバージョンによってはパターン変数を使えない場合があるため、その場合は従来のif (animal instanceof Dog)とブロック内キャストで対応できます。

⚠️ 注意: Objectから目的の型へ直接キャストする書き方は、呼び出し元と呼び出し先の約束が崩れた瞬間に例外へつながりますが、覚えておくと役立つでしょう。型が不確かな値は、キャスト前にinstanceof、形式変換、バリデーションのいずれかを通す設計が向いています。

キャストの詳細な対処法:よく遭遇する問題とその解決策

キャストで起こりやすい問題は、コンパイル時に見つかる型不一致と、実行時に発生する例外に分けられます。コンパイルエラーは構文や宣言型の矛盾として止まりますが、ClassCastExceptionNumberFormatExceptionは入力値や実体の型によって後から表面化するのが現実的です。

そのため、対処法はエラー種別ごとに変える必要があります。参照型の変換ではinstanceofやジェネリクスで型を絞り、文字列から数値への変換ではtrycatchで形式不正を扱います。

初心者がつまずきやすいのは、Objectに入っている値なら何にでも変えられると考えてしまう点です。Objectはあらゆる参照型の親ですが、親であることは別クラスへ変身できることを意味しません。

エラーと例外処理

ClassCastExceptionは、参照型のキャストが実体の型と合わない場合に発生すると整理できます。たとえばObject str = "Javaキャスト";で保持している実体はStringなので、Integerへ変換しようとしても成立しません。

一方、NumberFormatExceptionは、文字列解析で数値として読めない文字が含まれる場合に発生します。これはキャストの例外ではありませんが、型変換の文脈で同時に扱われやすい例外です。

具体的には、例外を捕捉してメッセージを返すだけでなく、どの値が期待と違ったのかを設計上で追えるようにします。Web APIならHTTPステータスやエラーレスポンス、バッチ処理ならログとスキップ判断を組み合わせますし、ここを基本と考えるとよいでしょう。

サンプルコード3:キャスト時のエラーハンドリング

次のコードは、Objectとして保持した文字列をIntegerへキャストしようとして失敗する例です。目的は例外の発生条件を示すことであり、文字列を整数へ変換する正しい方法は後段のInteger.parseIntになります。

public class Main {
    public static void main(String[] args) {
        try {
            Object str = "Javaキャスト";
            Integer num = (Integer) str;  // ここでClassCastExceptionが発生します
        } catch (ClassCastException e) {
            System.out.println("キャストに失敗しました。適切な型にキャストしてください。");  // この行はエラーメッセージを出力します
        }
    }
}

結果: 期待される出力はキャストに失敗しました。適切な型にキャストしてください。です。Stringの実体をIntegerへ直接変換できないため、catchブロックの処理に進みます。

このコードで学ぶべき点は、例外を握りつぶすことではなく、失敗する前提をどこで扱うかです。入力値の形式が問題ならparseInt、参照型の実体が問題ならinstanceof、設計上の型が広すぎるなら戻り値や引数の型を見直します。

一般に、例外処理は利用者向けの表示と開発者向けの原因追跡を分けて考えますし、ここがポイントです。画面やAPIレスポンスには過度な内部情報を出さず、ログには例外クラス、対象値の種類、処理名を残す設計が扱いやすいでしょう。

キャストの詳細な注意点:安全なコーディングのために

キャストを安全に使うには、変換前の値がどの型で、変換後に何をしたいのかを分けて考えます。目的が計算なら数値変換、目的が文字列解析ならパース、目的が子クラス固有メソッドの呼び出しなら参照型の確認が必要になります。

そのため、(Integer)(String)(Car)のような構文を見たら、周辺コードで型保証がどこにあるかを確認すると理解できます。保証が見つからないキャストは、将来の修正で壊れやすい箇所として扱うのが現実的です。

特に押さえたいのは、キャストと変換メソッドの違いです。(int)は数値型の表現を変える構文ですが、Integer.parseIntは文字列を解析して整数値を作るメソッドになります。

安全なキャストの方法

安全なキャストでは、変換前に条件を確認します。参照型ならinstanceof、文字列なら空文字や形式、数値なら範囲や丸め規則を見ますが、これは押さえたい点です。

一方、変換先の型を安易に広げる対応は避けたいところです。すべてをObjectMap<String, Object>に寄せると、一時的には書きやすく見えても、取り出し側にキャストと例外処理の負担が移ります。

具体的には、メソッドの戻り値をStringと決められるならObjectで返さず、複数項目を返すならrecordやDTOを使います。型の約束を宣言に出せば、キャストの出番は自然に減りますし、これが一つの目安です。

サンプルコード4:安全なキャストの実例

次のコードは、文字列"12345"を整数として読み取り、Integerへ代入する例です。文字列から数値への処理はキャストではなくInteger.parseIntを使い、形式が不正な場合はNumberFormatExceptionで扱います。

public class SafeCastingExample {
    public static void main(String[] args) {
        String strNumber = "12345";
        try {
            // String型からint型への変換
            int number = Integer.parseInt(strNumber);
            // int型からInteger型へのオートボクシング
            Integer integerNumber = number;
            System.out.println("変換成功: " + integerNumber);
        } catch (NumberFormatException e) {
            System.err.println("変換失敗: 不正な形式の文字列です。");
        }
    }
}

結果: 期待される出力は変換成功: 12345です。strNumberが数値として解析できる形式なので、intへの変換後にIntegerへオートボクシングされます。

この処理でstrNumber"12A"のような値になると、Integer.parseIntNumberFormatExceptionを投げます。そのため、外部入力を扱うコードではtrycatch、または事前バリデーションを組み合わせる必要があると覚えるとよいでしょう。

ちなみに、Integer integerNumber = number;では明示的なnew Integerは使いません。ラッパークラスのコンストラクタは非推奨になっているため、オートボクシングやInteger.valueOfを使う書き方が現在の選択肢になります。

ℹ️ 補足: StringIntegerへ変える処理はキャストではありません。文字列を解析して新しい数値を得る処理なので、形式不正への備えを同時に書くと読みやすくなります。

キャストの詳細なカスタマイズ:効率的なプログラミング

キャストのカスタマイズとは、必要な場所だけで型を狭め、不要なキャストを設計で減らす考え方です。ポリモーフィズムを活かせる場面では親型やインターフェースのまま扱い、子クラス固有の処理が本当に必要な箇所だけダウンキャストすると考えられます。

その発想は、Javaアノテーションの解説で触れるフレームワーク処理や、Javaエスケープ処理のような入力値処理とも関係します。型と値の性質を分けて扱うほど、処理の境界が読み取りやすくなります。

一方、すべての分岐をinstanceofで書き連ねると、クラスが増えたときに修正箇所が広がりますが、覚えておくと役立つでしょう。共通の振る舞いを親クラスやインターフェースに置けるなら、キャストではなくオーバーライドで解決するほうが自然です。

キャストとポリモーフィズム

ポリモーフィズムは、同じ型の参照から異なる実装のメソッドを呼び出せる仕組みです。Vehicle型の変数にCarを代入してdisplayを呼ぶと、実体であるCar側の@Overrideされたメソッドが選ばれます。

ただし、親型の参照から呼べるのは親型に定義されたメンバーです。Carだけが持つcarFeatureを呼びたい場合には、実体がCarであることを確認してからCar型として扱います。

基本的に、親型に共通操作を置けるならダウンキャストを減らせますし、ここを基本と考えるとよいでしょう。逆に、子クラス固有の処理を呼び分ける必要が何度も出るなら、クラス設計やインターフェース設計を見直す合図になります。

サンプルコード5:カスタマイズされたキャストの利用

// 親クラス
class Vehicle {
    void display() {
        System.out.println("これは車両です");
    }
}

// 子クラス
class Car extends Vehicle {
    @Override
    void display() {
        System.out.println("これは車です");
    }

    void carFeature() {
        System.out.println("車の特性を表します");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle myVehicle = new Car(); // アップキャスト
        myVehicle.display(); // ポリモーフィズムによるメソッドのオーバーライド

        Car myCar = (Car) myVehicle; // ダウンキャスト
        myCar.carFeature(); // サブクラスの特定のメソッドの利用
    }
}

結果: 期待される出力はこれは車です車の特性を表しますです。myVehicleの実体がnew Car()なので、(Car) myVehicleのダウンキャストは成立します。

この例では、displayの呼び出しにキャストは不要です。親クラスVehicleに定義されたメソッドが、実体のCar側で上書きされているため、Javaの動的ディスパッチによって子クラス側の処理が選ばれます。

これは車です
車の特性を表します

結果: 期待される表示例は、displayによるこれは車ですと、carFeatureによる車の特性を表しますの二行です。この出力例は直前のクラス構成を前提にしたものです。

そのまま使うなら、ダウンキャストの前にif (myVehicle instanceof Car myCar)を入れると、後からVehicle myVehicle = new Vehicle();に変わった場合にも例外を避けられます。型が変わる可能性のある参照ほど、チェックを近くに置くと読みやすくなります。

応用例とサンプルコード:より深く、より実践的に

応用的なコードでは、キャストそのものよりも、キャストが必要になった理由を読む力が求められますし、ここがポイントです。フレームワークの戻り値がObjectなのか、コレクションの値型を広く取りすぎたのか、外部入力が文字列として届いたのかで対処が変わります。

この観点は、日付や数値の入力を扱うJavaでうるう年を判定する解説にもつながります。値の妥当性を確認してから処理へ渡す流れは、キャストの安全性を高める考え方と同じです。

具体的には、サービス層から戻る型を明確にする、DTOやrecordを使う、Map<String, Object>を使う場合はキーごとの値型を文書化する、といった整理が効果的です。キャストを書く前に型の境界を整えると、例外処理の範囲も限定できると言えるでしょう。

応用例1:フレームワークとの連携

Springのようなフレームワークでは、サービス、コントローラ、リポジトリの層を分けて値を受け渡します。戻り値をObjectにすると柔軟に見えますが、呼び出し側が毎回StringやDTOへキャストする必要が出ます。

一方、戻り値をStringや専用レスポンス型にできるなら、コンパイル時に型の不一致を検出しやすくなるのが基本です。フレームワーク連携では、キャストで調整するより、層の境界で型を明確にする設計のほうが保守しやすいでしょう。

サンプルコード6:フレームワーク内でのキャスト利用

次のコードは、サービスからObjectとして受け取った値をStringにキャストして返す例です。説明用としては分かりやすい一方、実際の設計ではSampleServiceの戻り値をStringにできないか検討する余地があります。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SampleController {

    @Autowired
    private SampleService sampleService;

    @GetMapping("/sample")
    public String getSample() {
        Object response = sampleService.getSampleData();
        return (String) response; // キャストの利用例
    }
}

結果: 期待される挙動は、sampleService.getSampleData()Stringを返す場合に、その文字列を/sampleのレスポンスとして返すことです。戻り値の実体がStringでなければ、ClassCastExceptionが発生する可能性があります。

このコードでは@RestController@GetMapping@Autowiredが使われています。アノテーション自体はキャストを安全にするものではないため、SampleServiceの戻り値型を具体化するか、少なくとも戻り値の契約を明確にしておく必要があるのが目安です。

ただし、外部ライブラリや古いAPIの都合でObjectを受け取らざるを得ない場合もあります。その場合はif (response instanceof String text)で分岐し、違う型だったときのレスポンスや例外を明確にします。

応用例2:複雑なデータ構造とキャスト

複雑なデータ構造では、キーごとに異なる型の値を入れるためにMap<String, Object>が使われることがあるのがポイントです。この書き方は柔軟ですが、取り出すたびに値の型を利用側が知っている必要があります。

そのため、nameStringageIntegerheightDoubleという約束がコード外に散らばると、変更に弱くなります。可能なら専用クラスやrecord PersonData(String name, int age, double height)のような型で表現するほうが明確です。

一方、設定値、外部APIの一時的な受け皿、ログ用の属性などではMapが現実的な場合もあるのが一般的です。その場合は、取り出し箇所で型を確認し、期待と違う値が入ったときの扱いを決めます。

サンプルコード7:複雑なデータ構造でのキャスト

import java.util.HashMap;
import java.util.Map;

public class ComplexDataStructureCast {
    public static void main(String[] args) {
        // HashMapのインスタンス化
        Map<String, Object> dataMap = new HashMap<>();

        // 複数の異なるデータ型を格納
        dataMap.put("name", "山田太郎");
        dataMap.put("age", 30);
        dataMap.put("height", 175.5);

        // キャストを利用してデータを取り出し
        String name = (String) dataMap.get("name");
        Integer age = (Integer) dataMap.get("age");
        Double height = (Double) dataMap.get("height");

        // 取り出したデータの表示
        System.out.println("名前: " + name);
        System.out.println("年齢: " + age);
        System.out.println("身長: " + height);
    }
}

結果: 期待される出力は、名前: 山田太郎年齢: 30身長: 175.5の三行です。putした値の型と取り出し時のキャスト先が一致しているため、各値を目的の型として扱えます。

この例は分かりやすい反面、キー名の打ち間違いや値型の変更に弱い構造です。たとえばdataMap.put("age", "30")のように文字列で格納されると、(Integer) dataMap.get("age")は失敗します。

名前: 山田太郎
年齢: 30
身長: 175.5

結果: 期待される表示例は、Mapから取り出した三項目を行ごとに出す形式です。この出力はnameageheightの値型がコード中のキャスト先と一致している場合に成り立ちますが、これは押さえたい点です。

そのため、複雑なデータ構造を扱うときは、キャストを置く位置を限定します。取り出し処理をメソッド化し、getStringgetIntegerのような補助メソッドで型確認とエラー処理をまとめると、利用側のコードが読みやすくなります。

まとめ

Javaのキャストは、型が違う値を扱うための構文であり、数値型と参照型で判断基準が変わりますし、これが一つの目安です。数値型では範囲、精度、小数部の扱いを確認し、参照型では継承関係と実体のクラスを確認します。

そのうえで、intからdoubleのような拡大変換は比較的扱いやすく、doubleからintのような縮小変換では値の欠落に注意します。StringからIntegerのような変換はキャストではなく、Integer.parseIntによる解析として扱いるのが現実的です。

一方、オブジェクト型のキャストではClassCastExceptionが代表的な失敗になります。Objectや親クラス型の参照を子クラスへ変えるときは、instanceofで確認してから処理を進める書き方が読みやすくなります。

具体的には、Map<String, Object>、フレームワークの戻り値、外部入力の文字列など、型が広くなりやすい場所ほど慎重に扱いると整理できます。必要な型をメソッド引数、戻り値、ジェネリクス、DTOで表現できれば、キャストの量を減らせます。

キャストを読むときは、変換前の型、変換後の型、失敗条件、失敗時の処理を並べて確認します。この四点が見えるコードは、初心者にも保守担当者にも意図が伝わりやすく、Javaの型システムを活かした実装になると理解できます。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。