Java 入門

Java 型変換とキャスト

型変換(Type conversion)とキャスト(Casting)は、Java において極めて基礎的でありながら、ミスを誘発しやすい概念です。これらをマスターすることで、異なるデータ型を効率的に操作する能力が身に付きます。

Java は強力な型付け(Strongly-typed language)が行われる言語であり、すべての変数には厳格なデータ型が定められています。数学的計算の実行、ユーザー入力の処理、そして頭の痛いコンパイルエラーや実行時エラーを回避するために、型変換の仕組みを理解することは極めて重要です。

本章では、型変換の種類、それらが必要になるタイミング、および安全に操作を実行する方法について包括的にカバーします。

1. 暗黙的型変換 (自動拡大変換 / Widening)

暗黙的型変換は、「自動アップキャスト」や「拡拡大変換」とも呼ばれます。これは、小さなデータ型の値を大きなデータ型の変数に代入するときに自動的に発生します。ターゲットとなるコンテナ(変数)が元のデータよりも大きいため、この変換は絶対に安全であり、情報が失われるリスクはありません。

1.1 自動変換はどのように機能するのか?

Java コンパイラは、プログラマが特別なコードを書くことなく、バックグラウンドで小さな型を大きな型へ自動的に変換します。以下の変換パスは、自動的に発生することが許可されています。

  • byteshort, int, long, float, または double
  • shortint, long, float, または double
  • charint, long, float, または double
  • intlong, float, または double
  • longfloat または double
  • floatdouble

1.2 暗黙的変換のコード例

public class ImplicitConversion {
    public static void main(String[] args) {
        int intValue = 100;
        
        // 暗黙的変換:小さなカップ (int) から大きなカップ (long) へ注ぐ。自動的に完了。
        long longValue = intValue; 
        System.out.println("Long 値: " + longValue); // 出力: Long 値: 100
        
        // 暗黙的変換:long から float への変換
        float floatValue = longValue; 
        System.out.println("Float 値: " + floatValue); // 出力: Float 値: 100.0
        
        // 暗黙的変換:float から double への変換
        double doubleValue = floatValue; 
        System.out.println("Double 値: " + doubleValue); // 出力: Double 値: 100.0
        
        // 特殊なケース:char から int への自動変換 (文字に対応する ASCII/Unicode 値へ変換)
        char charValue = 'A';
        int intFromChar = charValue; 
        System.out.println("文字から Int への変換: " + intFromChar); // 出力: 65
    }
}

2. 明示的型変換 (強制型変換 / Casting)

明示的型変換は、「ダウンキャスト」または「縮小変換」とも呼ばれます。大きなデータ型の値を小さなデータ型の変数に押し込もうとする場合には、この方法を使用しなければなりません。

大きなカップの水を小さなカップに注ぐと溢れる可能性があるように、これは潜在的なデータ欠落のリスクを意味します。そのため、Java コンパイラはこの操作が自動的に行われることを許可しません。プログラマが「キャスト演算子」を明示的に記述することで、自分が何をしているかを理解しており、データ損失の結果を受け入れることを証明する必要があります。

2.1 キャストの構文構造

キャストの構文は、変換したい値の前に小括弧 () でターゲットとなるデータ型を囲みます。つまり、(ターゲット型) 値 となります。

以下の「逆方向」の操作にはすべてキャストが必要です。

  • shortbyte または char
  • charbyte または short
  • intbyte, short, または char
  • longbyte, short, char, または int
  • floatbyte, short, char, int, または long
  • doublebyte, short, char, int, long, または float

2.2 キャストのコード例とリスクのデモンストレーション

public class ExplicitConversion {
    public static void main(String[] args) {
        // 1. 精度欠落 (Truncation)
        double doubleValue = 19.99;
        int intValue = (int) doubleValue; // 強制的に double を int へ変換
        System.out.println("Double から Int へのキャスト: " + intValue); // 出力: 19 (小数部分は切り捨てられ、四捨五入されません!)

        // 2. 正常なキャスト (数値が安全な範囲内にある場合)
        long longValue = 200L;
        int intValueFromLong = (int) longValue; 
        System.out.println("Long から Int へのキャスト: " + intValueFromLong); // 出力: 200

        // 3. データオーバーフロー (Overflow) - 極めて危険!
        int largeIntValue = 130;
        // byte の最大容量は 127 です。130 を無理やり押し込むとどうなるでしょうか?
        byte byteValueFromInt = (byte) largeIntValue; 
        System.out.println("大きな Int から Byte へのキャスト: " + byteValueFromInt); // 出力: -126 (低レイヤーでのラップアラウンドが発生)
    }
}

データオーバーフロー (Overflow) の深い理解:

上記のコードにおいて、byte の取值範囲は -128 から 127 です。130 を byte にキャストしようとしても、収まりきりません。これは車の走行距離計が最大値を超えると 0 に戻るのと同じ仕組みです。130 は最大値 127 よりも 3 ユニット多いため、最小値へと「ラップアラウンド」し、-128 + (3 - 1) = -126 となります。実際のビジネスロジックにおいて、これは致命的なバグの原因となります。

3. 文字列と基本データ型の相互変換

Java では、ユーザーが入力したテキスト(文字列)を計算のために数値に変換したり、計算結果の数値を画面に表示するためにテキストに変換したりすることが頻繁にあります。注意点として、文字列の変換には前述の (int) のような括弧を使ったキャスト構文は使えません。 文字列変換には特定のクラスが提供するメソッドを呼び出す必要があります。

3.1 文字列から基本データ型への変換 (Parsing)

数値を表す文字列を基本データ型に変換するには、対応する「ラッパークラス (Wrapper Class)」の parseXxx() メソッドを使用します。

public class StringToPrimitive {
    public static void main(String[] args) {
        // 文字列から int へ
        String intString = "123";
        int intValue = Integer.parseInt(intString);
        System.out.println("解析された Int: " + intValue); // 出力: 123
        
        // 文字列から double へ
        String doubleString = "45.67";
        double doubleValue = Double.parseDouble(doubleString);
        System.out.println("解析された Double: " + doubleValue); // 出力: 45.67
        
        // 文字列から boolean へ (文字列が "true" の場合のみ真となる、大文字小文字は無視される)
        String booleanString = "TrUe";
        boolean booleanValue = Boolean.parseBoolean(booleanString);
        System.out.println("解析された Boolean: " + booleanValue); // 出力: true
    }
}

致命的な警告:
文字列に有効な数値が含まれていない場合(例:"123a""hello")、Integer.parseInt() を呼び出すとその場でプログラムがクラッシュし、NumberFormatException という例外がスローされます。実際の開発では、この例外を適切に処理する必要があります(これについては後の例外処理モジュールで詳しく学習します)。

3.2 基本データ型から文字列への変換

数値やブーリアン値を文字列に変換するのは非常に簡単です。最も標準的で推奨される方法は String.valueOf() を使用することです。

public class PrimitiveToString {
    public static void main(String[] args) {
        int intValue = 123;
        // 標準的な手法:String.valueOf() を使用
        String intString = String.valueOf(intValue); 
        System.out.println("文字列への変換: " + intString);
        
        double doubleValue = 45.67;
        String doubleString = String.valueOf(doubleValue);
        
        boolean booleanValue = true;
        String booleanString = String.valueOf(booleanValue); 

        // もう一つの一般的な手法:空の文字列と連結する (内部的な自動変換機能を利用)
        int anotherInt = 999;
        String easyString = anotherInt + ""; 
        System.out.println("連結法による文字列変換: " + easyString);
    }
}