本ページはプロモーションが含まれています

Java入門

Javaのキャスト完全ガイド|ClassCastException対策

CATEGORY
REV.
DRAWN BY
TOM
SHEETS
7枚
(Cast)(ClassCastException対策)

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

𝕏

Javaのキャストとは、(int) 3.99や(Dog) animalのように(型名)を付けて、値やオブジェクトを別の型として扱う型変換のことです。

私も最初はアップキャストとダウンキャストの違いを理解しないまま、なんとなくキャストを書いていました。

押さえるポイントは3つです。数値は小さい型から大きい型へは自動で変換され、逆向きは(int)などの明示キャストが必要で値が切り捨てられます。クラスはアップキャストが自動、ダウンキャストは明示的に書く必要があります。そしてダウンキャストはinstanceofで実体の型を確かめないとClassCastExceptionになります。

この記事でわかること

  • int・doubleなど数値型のキャストの書き方と注意点
  • アップキャスト・ダウンキャストの仕組みと違い
  • instanceofによる安全なダウンキャストの方法
  • ClassCastExceptionの原因と対策
トム
トム

正直、最初は例外メッセージを見ても何が起きているのかさっぱりでした。

Javaのキャストとは?書き方と型変換の基本

キャストとは、ある型のデータを別の型として扱えるように変換することです。

Javaのキャストには、プリミティブ型同士の変換と、クラスの継承関係を利用した参照型同士の変換の2種類があります。

プリミティブ型変換と参照型変換は仕組みがまったく違うため、混同すると理解が混乱します。

プリミティブ型キャストと参照型キャストの違い

プリミティブ型のキャストは、int型をdouble型に変換するような、数値の表現形式を変える処理です。

一方、参照型のキャストは、実体(インスタンス)は変えずに「どの型として扱うか」というラベルを変える処理です。

参照型キャストではインスタンスの中身は一切変わらず、コンパイラに対して「この変数をこの型として扱ってよい」と伝えているだけになります。

暗黙的キャストと明示的キャストの違い

int型からlong型への変換のように、値の大きさが変わらない拡大変換は自動的に行われます。これを暗黙的キャストと呼びます。なお、int型やlong型からfloat型への変換は自動で行われますが、有効桁数が足りず下位の桁が丸められる場合があります(例: intの123456789をfloatに入れてintへ戻すと123456792になります)。

逆に、double型からint型への変換のように情報が失われる可能性がある変換は、(int) 3.14のように明示的にキャストを書く必要があります。

参照型のアップキャストも暗黙的に行われ、ダウンキャストは明示的に書く必要があるという点で、この考え方は共通しています。

数値型で自動変換(暗黙的キャスト)される向きを表にすると、次のとおりです。

変換の向き書き方例
byte → short → int → long → float → double(左から右)自動(キャスト不要)long l = 100;
char → int自動(キャスト不要)int code = 'A'; // 65
double → int など(右から左)明示キャストが必要int i = (int) 3.99; // 3

プリミティブ型キャストで精度が落ちる具体例

明示的なキャストは、値そのものを壊してしまうことがあります。

doubleからintへの変換では小数点以下がそのまま切り捨てられ、longからintへの変換では扱える桁数を超えてオーバーフローが起きます。

double d = 3.99;
int i = (int) d; // 3(小数点以下が切り捨てられる)

long l = 10000000000L;
int overflow = (int) l; // 桁あふれで想定外の値になる

参照型のダウンキャスト失敗が実行時例外を投げるのに対し、プリミティブ型のキャストは値が壊れても例外を投げません。

エラーにならないぶん、精度が落ちたことに気づきにくいのが実務での落とし穴です。

int同士の割り算で小数を得るキャストの書き方

数値のキャストが一番よく登場するのは、int同士の割り算で小数点以下まで求めたい場面です。

int同士で割ると結果もintになるため、代入先をdoubleにしても小数点以下は失われます。

int a = 7;
int b = 2;

double r1 = a / b;            // 3.0(int同士で割ってからdoubleになる)
double r2 = (double) a / b;   // 3.5(aを先にdoubleへ変換してから割る)
double r3 = (double) (a / b); // 3.0(割り算の結果をキャストしても手遅れ)
割る前にどちらか一方を(double)でキャストすれば、割り算そのものがdoubleで計算されます。

(double) (a / b)のように割り算の結果をキャストしても、intで割った時点で切り捨てが済んでいるため3.0のままです。キャストを書く位置で結果が変わる点に注意してください。

文字列⇔数値の変換はキャストと呼ばない

「キャスト」と検索する人の中には、文字列と数値の変換方法を探している場合もあります。

しかしString.valueOf()やInteger.parseInt()はキャスト演算子ではなく、メソッド呼び出しによる変換です。

実際、(String) 10のようにint型やdouble型の値をStringへキャストしようとすると、「不適合な型」のコンパイルエラーになります。

型変換全般を「キャスト」と呼んでしまう混同はよくあるつまずきポイントなので、演算子によるキャストとメソッドによる変換は別物だと切り分けておくと理解が整理されます。

アップキャスト|サブクラスからスーパークラスへの変換

アップキャストは、サブクラスのインスタンスをスーパークラスの型として扱う変換です。安全な変換のため、Javaが自動的に行ってくれます。

アップキャストが自動で行われる仕組み

サブクラスは必ずスーパークラスの機能をすべて持っています。

そのため、サブクラスのインスタンスをスーパークラス型の変数に代入しても、情報が失われることはありません。

この安全性が保証されているからこそ、コンパイラは明示的なキャストを要求せず、自動で変換してくれます。

class Animal {}
class Dog extends Animal {
    void bark() { System.out.println("わん"); }
}

Dog dog = new Dog();
Animal animal = dog; // 暗黙的にアップキャストされる
あわせて読む

アップキャスト後に呼び出せるメソッドの制限

アップキャストした変数からは、スーパークラスで定義されているメソッドしか呼び出せません。

上の例で言えば、animal変数からbark()メソッドを呼ぶことはできません。

インスタンスの実体はDogのままですが、変数の型がAnimalになった時点で扱いが変わります。

コンパイラはAnimalが持つメソッドしか知らない扱いになるためです。

アップキャストを使うと何が便利になるか

アップキャストが真価を発揮するのは、異なるサブクラスのインスタンスをまとめて扱いたいときです。

List<Animal>という1つのリストにDogやCatのインスタンスを格納し、ループで一括処理できます。

List<Animal> animals = new ArrayList<>();
animals.add(new Dog());
animals.add(new Cat());

for (Animal animal : animals) {
    animal.makeSound(); // それぞれのサブクラスの実装が呼ばれる
}

この仕組みはポリモーフィズム(多態性)と呼ばれ、呼び出す側はDogかCatかを意識せず、共通の窓口(Animal型)を通して扱えます。

アップキャストは制約ではなく、こうした柔軟な設計を可能にするための手段だと捉えると理解しやすくなります。

Java Silver試験の対策でも、ポリモーフィズムを絡めたキャストは押さえておきたいテーマです。

ダウンキャスト|スーパークラスからサブクラスへの変換

ダウンキャストは、スーパークラス型の変数をサブクラス型に戻す変換です。

アップキャストとは逆に、実体がキャスト先の型とは限らず、実行時に失敗するおそれがあるため、明示的にキャストを書く必要があります。

ダウンキャストが必要になる場面

アップキャストで失われたサブクラス固有のメソッドを再び使いたいときに、ダウンキャストが必要になります。

先ほどの例でanimal変数からbark()を呼びたい場合、(Dog) animalのように明示的にキャストすれば、再びbark()を呼び出せるようになります。

ただし、ダウンキャストが頻繁に必要になるコードは、そもそもクラス設計を見直すサインになりえます。

ポリモーフィズムを活かした設計にできれば、ダウンキャストなしで済むケースは意外と多くあります。

Animal animal = new Dog();
Dog dog = (Dog) animal; // ダウンキャスト
dog.bark();

ダウンキャストが失敗する条件

ダウンキャストが成功するのは、変数の実体が本当にキャスト先の型である場合だけです。

実体がCatのインスタンスなのに(Dog) animalと書いてしまうと、実行時にClassCastExceptionが発生します。

コンパイル時には型チェックが通ってしまうため、この失敗は実行してみるまで気づけないのが厄介な点です。

キャストで変わるのは「変数の型」だけ(実体は変わらない)
CODE / コード
変数の型
実体
結果
Dog dog = new Dog();① Dog 型の変数で扱う
Dog 型
Dog
○ bark() を呼べる
Animal a = dog;② アップキャスト(自動)
Animal 型
Dog
✕ bark() は呼べないAnimal のメソッドしか呼べない
Dog d = (Dog) a;③ ダウンキャスト(明示)
Dog 型
Dog
○ 成功 → bark() を呼べる
Dog d = (Dog) a;④ a の実体が Cat の場合
Dog 型
Cat
✕ 実行時に ClassCastExceptionコンパイルは通る
NOTE①〜③で実体はずっと同じ Dog のまま。Dog・Cat は Animal を継承したサブクラスという記事中の例です。④は実体が Cat なので、(Dog) にすると実行時に失敗します。

実際に実行すると、次のような例外メッセージが出力されます。「class A cannot be cast to class B」と出たら、Aが実体の型、Bがキャストしようとした型です。

Animal animal = new Cat();
Dog dog = (Dog) animal; // 実体はCatなので実行時に失敗する

// 実行結果(Java 23で確認)
// Exception in thread "main" java.lang.ClassCastException:
//   class Cat cannot be cast to class Dog ...
あわせて読む

アップキャストとダウンキャストの違い一覧

項目アップキャストダウンキャスト
変換の向きサブクラス → スーパークラススーパークラス → サブクラス
書き方自動(Animal a = dog;)明示(Dog d = (Dog) a;)
安全性常に成功する実体の型が違うと失敗する
失敗したとき-実行時にClassCastException
主な用途サブクラスをまとめて扱う(ポリモーフィズム)サブクラス固有のメソッドを呼ぶ

instanceofで安全にダウンキャストする方法

ダウンキャストの失敗を防ぐには、キャストする前に実体の型を確認するinstanceof演算子を使います。

参照型をキャストするときの判断の流れを図にすると、次のようになります。

参照型をキャストするときの判断フロー(Q1から順に答える)
QUESTION / 質問
はい
いいえ
Q1. 変換の向きは サブクラス → スーパークラス?参照型の変数を別の型で扱いたいとき
アップキャスト自動で変換され、常に成功
スーパークラス → サブクラス。Q2へ
Q2. instanceof で確認した実体の型はキャスト先?a instanceof Dog が true か
Q3へ
キャストしないそのまま書くと ClassCastException
Q3. Java 16以降?
if (a instanceof Dog d)パターンマッチングで d をそのまま使う
if (a instanceof Dog) の中で (Dog) a明示的にキャストする
ダウンキャストのNG例とOK例
NG / 確認せずにキャストDog dog = (Dog) animal;✕ 実体が異なる型のときに ClassCastException が発生する
OK / instanceof で確認してからif (animal instanceof Dog) { Dog dog = (Dog) animal; }○ 型を確認してからキャストするため、ClassCastException が発生しない

instanceof演算子による事前チェック

if (animal instanceof Dog)のように書けば、animalの実体がDogかどうかを事前に確認できます。

この条件が true のときだけダウンキャストすれば、ClassCastExceptionを未然に防げます。
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();
}

Java 16以降のパターンマッチングinstanceof

Java 16以降では、instanceofのチェックとキャストを1行にまとめられるパターンマッチングが使えます。

if (animal instanceof Dog d)と書くだけで、条件がtrueのブロック内では自動的にdという変数がDog型として使えるようになります。

従来のようにinstanceofでチェックしてから改めてキャストする2段階の記述が不要になり、コードが簡潔になります。

if (animal instanceof Dog d) {
    d.bark(); // キャスト済みのdをそのまま使える
}

ClassCastExceptionの原因と対策

ClassCastExceptionは実務でも起こりやすいバグの1つです。原因を型ごとに把握しておくと、初動の切り分けが速くなります。

トム
トム

私も本番障害の一次対応で真っ先に疑うのがこのパターンです。

よくある発生パターン3つ

1つ目は、兄弟クラス間の誤ったキャストです。

DogとCatが同じAnimalを継承していても、CatのインスタンスをDogにキャストすることはできません。

2つ目は、リストの要素を誤った型で受け取るケースです。

List<Object>から取り出した要素を安易に特定の型へキャストすると、実体が違う型だった場合に例外が発生します。

3つ目は、外部から受け取ったデータの型を確認せずにキャストするケースです。

JSONのデシリアライズ結果など、実行時まで型が確定しないデータで起こりやすいバグです。

instanceof確認を省略してしまう大きな理由の1つは、開発中は型が一致していて問題が表面化しないためです。

テストデータが偏っていると発見が遅れ、本番環境で想定外のデータが来て初めて例外に気づくことも珍しくありません。

ジェネリクスとの組み合わせで起きる注意点

ジェネリクスを使ったコレクションは、コンパイル時に型消去が行われるため、実行時には型情報が残っていません。

そのため、List<Dog>とList<Cat>を混同するようなミスは、raw型やObject型を経由した無検査キャストの警告を無視した場合にだけ発生します。

ジェネリクスの型パラメータを安易にキャストで誤魔化すコードを見かけたら、設計自体を見直すサインだと捉えたほうがよいです。

よくある質問

Q. アップキャストとダウンキャストはどちらが危険ですか?
A. ダウンキャストの方が危険です。実体と異なる型へダウンキャストするとClassCastExceptionが発生するため、instanceofで事前確認するのが安全です。

Q. instanceofを使えばキャストは絶対に失敗しませんか?
A. はい。instanceofで型を確認してからキャストすれば、その時点での型不一致によるClassCastExceptionは防げます。

Q. プリミティブ型のキャストでClassCastExceptionは起きますか?
A. いいえ。ClassCastExceptionは参照型のキャストで発生する例外です。プリミティブ型の変換で情報が失われる場合は、例外ではなく値の精度が落ちる形で処理されます。

Q. Java 16のパターンマッチングinstanceofは古いJavaでも使えますか?
A. いいえ。Java 16以降でのみ使用できます。それより前のバージョンでは、従来通りinstanceofとキャストを分けて書く必要があります。

Q. 兄弟クラス同士のキャストはなぜできないのですか?
A. 継承関係にないためです。DogとCatが同じAnimalを継承していても、DogとCatの間には親子関係がないため、Cat型の変数を(Dog)でキャストするとコンパイルエラーになります。Animal型の変数に入ったCatを(Dog)でキャストした場合は、コンパイルは通り、実行時にClassCastExceptionが発生します。

Q. ジェネリクスのキャストで警告が出るのはなぜですか?
A. コンパイル時の型消去により、実行時にはジェネリクスの型パラメータの情報が残らないためです。

List<Dog>をList<Cat>へ直接キャストするとコンパイルエラーになりますが、Object型などを経由して無理にキャストすると、コンパイラは無検査キャスト(unchecked)の警告を出します。

あわせて読みたい

まとめ|キャストはinstanceofで安全性を確保する

Javaのキャストで押さえておきたいポイントは、次の3点です。

  • アップキャストは自動・安全、ダウンキャストは明示的でリスクを伴う
  • ダウンキャストの前にはinstanceofで実体の型を確認する
  • Java 16以降ならパターンマッチングinstanceofでコードを簡潔にできる

ClassCastExceptionは実行してみるまで気づきにくいバグですが、instanceofで事前確認する習慣さえ身につければ、ほとんどのケースは未然に防げます。

キャストを書くときは、まず「この変換は本当に安全か」を一度立ち止まって考えてみてください。

REVISIONS / 改訂履歴
REV.DATE内容
32026-10-16図解を描き直し(図面のデザインにそろえた)
22026-10-04記載内容の事実確認と修正
12026-08-29初版
NEXT READ本棚から1本

AIで開発を組み直すなら、まずこの5冊から

入門・実践・設計まで、Claude Codeの本をレベル別に5冊選んで比べました。

→ おすすめ5冊を見る

  • この記事を書いた人
  • 最新記事

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

𝕏

Java入門 ・