Javaの道 Javaに関する
 ニュースJava基本Servlet・JSPオープンソースFAQ掲示板
Javaの道 > Java基本 > クラス −14.参照型の型変換とキャスト
更新日:2005/7/25
クラス−14.参照型の型変換とキャスト
Javaの変数には大きく分けて2つの型があります。基本型(プリミティブ型)と参照型(オブジェクト型)です。参照型にはクラス型、インタフェース型、配列型があります。オブジェクトを生成する際、「String s = new("Hello");」と言う形でオブジェクトsを生成します。このオブジェクト変数sが、クラス型の変数と言えます。インタフェース型配列型に関しては、それぞれの該当ページを参照してください。

基本型はJavaであらかじめ用意されているboolean、char、byte、short、int、long、float、doubleの8つのデータ型です。

このページではある参照型の変数を、他の参照型の変数に変換する方法について説明します。変換には、Java実行環境により暗黙的に変換される型変換と、プログラマが意識的に変換を行うキャストがあります。なお、基本型の変数の変換に関しては、変数(基本型の型変換とキャスト)を参照してください。
参照型の型変換

参照型の型変換は基本的には、スーパークラス、スーパーインタフェース、(配列の場合は配列要素がスーパークラス、スーパーインタフェース)への変換をJava実行環境が要求した時に、暗黙的な型変換が行われます。

【型変換のルール】

変換元の参照型
変換先の参照型
型変換のルール
クラス型
クラス型
変換先のクラス型が変換元のクラス型のスーパークラスであること。
インタフェース型
変換先のインタフェース型のインタフェースを変換元のクラス型のクラスが実装していること。
配列型
型変換不可。
インタフェース型
クラス型
変換先のクラス型がObjectクラスであること。
インタフェース型
変換先のインタフェース型が変換元のインタフェース型のスーパーインタフェースであること。
配列型
型変換不可。
配列型
クラス型
変換先のクラス型がObjectクラスであること。
インタフェース型
変換先のインタフェース型がCloneableインタフェース、Serializableインタフェースであること。
配列型
変換元の配列要素のデータ型と、変換先の配列要素のデータ型において、型変換のルールに合致していること。

暗黙的な型変換は「代入時」と「メソッド呼び出し時」にJava実行環境より呼び出されます。以下では、それぞれのケースにおいて、どのように型変換が行われるのかについて説明します。

代入時の型変換

ある参照型の変数を、他の参照型の変数に代入する際に型変換が行われます。変換は【型変換のルール】に従います。

【例1変換元がクラス型、変換先がクラス型の例です。SuperClassクラスはSubClassクラスのスーパークラスであるとします。

SuperClass s1;
SubClass s2 = new SubClass();
s1 = s2;
//変換先の変数(s1)のクラス型は、変更元の変数(s2)のクラス型の
//スーパークラスであるため、型変換が行われ代入可能となります。

SuperClass s1 = new SuperClass();
SubClass s2;
s2 = s1;
//変換先の変数(s2)のクラス型は、変更元の変数(s1)のクラス型の
//スーパークラスではないため、コンパイルエラーとなります。

【例2変換元がクラス型、変換先がインタフェース型の例です。ExClassクラスはExInterfaceインタフェースを実装しているものとします。

ExClass class1 = new ExClass();
ExInterface interface1;
interface1 = class1;
//変換先の変数(interface1)のインタフェースは、
//変更元の変数(class1)のクラスで実装されているため、
//型変換が行われ代入可能となります。

ExClass class1 = new ExClass();
OtherInterface ointerface1;
ointerface1 = class1;
//変換先の変数(ointerface1)のインタフェースは、
//変更元の変数(class1)のクラスで実装されていないため、
//コンパイルエラーとなります。

【例3変換元が配列型、変換先が配列型の例です。SuperClassクラスはSubClassクラスのスーパークラスであるとします。

//SuperClassの宣言。
class SuperClass {
  public static void main(String[] args) {
    SuperClass[] superArray;  //(1)
    SubClass[] subArray = new SubClass[5];  //(2)

    for (int i = 0; i < subArray.length; i++) {  //(3)
      subArray[i] = new SubClass();
    }

    superArray = subArray;  //(4)代入による型変換
  }
}

//SubClassの宣言。SuperClassを継承。
class SubClass extends SuperClass {}

【解説3

(1). SuperClassクラスの配列superArrayを宣言しています。
(2). SubClassクラスの配列subArrayを宣言、生成しています。
(3). forループを使用し、配列subArrayの要素に対し、オブジェクトを生成しています。オブジェクトの配列を生成する場合は、個々の配列要素に対し、オブジェクトを生成する必要があります。
(4). 変換元の変数(subArray)を変換先の変数(superArray)に代入しています。superArrayの配列要素はsubArrayの配列要素のスーパークラスであるため、型変換が行われ、代入可能になります。
メソッド呼び出し時の型変換

メソッドを呼び出す際、呼び出すメソッドの引数の型に要求されている型と異なる型を指定した場合、暗黙的な型変換が行われます。その際の変換も「型変換のルール」に従います。

【例4メソッド呼び出し時に型変換が行われる例です。

String ex1 = new String("Hello");
StringBuffer ex2 = new StringBuffer("Hello");
boolean result = ex1.equals(ex2);
//equalsメソッドは引数にObject型の変数を要求します。
//Objectクラスはすべてのクラスのスーパークラスであるため、
//StringBuffer型の変数ex2はObject型に型変換され、equalsが
//実行されます。
//※Stringクラスのequalsメソッドは本来はString型の変数に
//使用します。

String ex1 = new String("Hello");
StringBuffer ex2 = new StringBuffer("Hello");
boolean result = ex1.equalsIgnoreCase(ex2);
//equalsIgnoreCaseメソッドは引数にString型の変数を要求し
//ます。
//変数ex2はStringBuffer型であり、【型変換のルール】にも合
//致しないため、コンパイルエラーとなります。
参照型のキャスト

キャストとはプログラマが意識的に行う変換処理です。キャストは変換したい型を( )で囲み、変換元の変数の前に指定することにより行います。

(変換したい型)変換元の変数;

参照型のキャストは基本型のキャストと異なり、コンパイル時のルールと実行時のルールを意識する必要があります。それは、参照型のデータには実体ではなく、実体が保存されている位置を表すアドレス情報が格納されているためです。

参照型データは以下の構成を取っています。データの実体は変数とは別の場所に格納され、参照型変数sには実体を参照するアドレス情報が格納されています。これが参照型と言われている理由です。

参照型データ

コンパイラは参照型の変数が参照する実体がどのようなものかはコンパイルする時点ではわかりません。そのため、コンパイル時にエラーが出なくても、実行する時点で初めて実行時のルールにそぐわないと判断され、エラーを生成します。コンパイル時のキャストのルールを以下に記載します。【実行時のキャストのルール】は【型変換のルール】と同様です。

【コンパイル時のキャストのルール】

変換元の参照型
変換先の参照型
型変換のルール
クラス型
クラス型
変換元のクラスと、変換先のクラスに継承関係があること。どちらが、スーパークラスであってもかまわない。
インタフェース型
すべてキャスト可能。
配列型
参照型の配列であること。
インタフェース型
クラス型
すべてキャスト可能。
インタフェース型
すべてキャスト可能。
配列型
キャスト不可。
配列型
クラス型
変換先のクラス型がObjectクラスであること。
インタフェース型
キャスト不可。
配列型
変換元の配列要素のデータ型と、変換先の配列要素のデータ型において、キャストのルールに合致していること。

※クラス型がfinal修飾子を実装したものである場合、上記のルールとは異なります。しかし頻繁に使用するケースではないため、ここでは割愛します。

【例5参照型のキャストの例です。
SuperClassAはSubClassA1のスーパークラスとします。
SuperClassAはSubClassA2のスーパークラスとします。

SubClassA1 a1 = new SubClassA1();
SuperClassA a;
SubClassA2 a2;

a = (SuperClassA)a1;  //(1)コンパイルOK、実行OK
a2 = (SubClassA2)a;  //(2)コンパイルOK、実行NG

【解説5

(1). 変数aと変数a1にはクラスの継承関係があるため、コンパイルは成功します。また、実体においても、変数aは変数a1のスーパークラスであるため、【実行時のキャストのルール】に合致し、 実行も成功します。
(2). 変数a2と変数aにはクラスの継承関係があるため、コンパイルは成功します。実体においては、変数aの実体は,蚤綟が行われているためSubClassA1です。変数a2の実体はSubClassA2です。SubClassA2はSubClassA1のスーパークラスではないため、 【実行時のキャストのルール】に合致せず、例外が返されます。



このページのトップへ
 ニュースJava基本Servlet・JSPオープンソースFAQ掲示板
Javaの道_CopyrightJavaの道