ダウンキャスト
日本語 | downcast |
英語 | 下キャスト |
ふりがな | だうんきゃすと |
フリガナ | ダウンキャスト |
あるクラスをサブクラスへとキャストすること。
キャストの一種。プリミティブ型のキャストと同じく、参照型変数の前に小カッコ「(」と「)」で変換先のサブクラスを記述することで、「見かけ上の型」をサブクラスへと変換することができる。
ただし、変換できるのは、そのインスタンスのクラスがキャスト先のクラスと全く同じ場合か、もしくはサブクラスの場合である。
ダウンキャストでは、渡される参照の値や、その参照が指し示すインスタンスは全く変化しない。変わるのは、参照を格納する、参照型変数の見かけ上の型だけである。
つまり、ダウンキャストを行っても「元々のインスタンスのクラス」がキャスト先のクラスに変換されるわけではない。たとえば、元々のインスタンスのクラスがIntegerクラスであり、それがObjectクラスの参照型に格納されていたとする。これをObjectのサブクラスLongクラスにダウンキャストした場合、ダウンキャストそのものは「サブクラスであれば可能」なためコンパイルは通るが、実行時、インスタンスのIntegerクラスと、ダウンキャスト先のLongクラスとでクラスが異なるため、ClassCastExceptionが発生する。実際のインスタンスはIntegerクラスのままであり、にも関わらずLongクラスとして扱われては問題だからである。
ダウンキャストとは逆に、スーパークラスへとキャストすることを「アップキャスト」と呼ぶ。通常、ダウンキャストは「元々のインスタンスをアップキャストしたもの」に対して、元々のインスタンスへと「元に戻す」ために行われる。そのため、ダウンキャストは本来、アップキャストしなければ必要ないものである。
ダウンキャスト、そしてその元となる不必要なアップキャストを乱発すると、プログラムを追っても実際の型が分からずClassCastExceptionが爆発的に発生する「ClassCastException地獄」に陥る危険性がある。対策として、不必要なアップキャストの削除やコレクションでのgenericsの検討といった「根治療法」の他、instanceofによるチェックや例外処理による「応急処置」などがある。
ダウンキャストはバグの原因として5本の指に入るものであり、できるだけ避けるべきである。ただし、現実的には不可避な面も多々あるため、上手に付き合うことが必要と言える。
ちなみに「down」なのは、クラスの継承関係において「サブクラス」が「スーパークラス」の「下」にあるためである。
キャストの一種。プリミティブ型のキャストと同じく、参照型変数の前に小カッコ「(」と「)」で変換先のサブクラスを記述することで、「見かけ上の型」をサブクラスへと変換することができる。
ただし、変換できるのは、そのインスタンスのクラスがキャスト先のクラスと全く同じ場合か、もしくはサブクラスの場合である。
ダウンキャストでは、渡される参照の値や、その参照が指し示すインスタンスは全く変化しない。変わるのは、参照を格納する、参照型変数の見かけ上の型だけである。
つまり、ダウンキャストを行っても「元々のインスタンスのクラス」がキャスト先のクラスに変換されるわけではない。たとえば、元々のインスタンスのクラスがIntegerクラスであり、それがObjectクラスの参照型に格納されていたとする。これをObjectのサブクラスLongクラスにダウンキャストした場合、ダウンキャストそのものは「サブクラスであれば可能」なためコンパイルは通るが、実行時、インスタンスのIntegerクラスと、ダウンキャスト先のLongクラスとでクラスが異なるため、ClassCastExceptionが発生する。実際のインスタンスはIntegerクラスのままであり、にも関わらずLongクラスとして扱われては問題だからである。
ダウンキャストとは逆に、スーパークラスへとキャストすることを「アップキャスト」と呼ぶ。通常、ダウンキャストは「元々のインスタンスをアップキャストしたもの」に対して、元々のインスタンスへと「元に戻す」ために行われる。そのため、ダウンキャストは本来、アップキャストしなければ必要ないものである。
ダウンキャスト、そしてその元となる不必要なアップキャストを乱発すると、プログラムを追っても実際の型が分からずClassCastExceptionが爆発的に発生する「ClassCastException地獄」に陥る危険性がある。対策として、不必要なアップキャストの削除やコレクションでのgenericsの検討といった「根治療法」の他、instanceofによるチェックや例外処理による「応急処置」などがある。
ダウンキャストはバグの原因として5本の指に入るものであり、できるだけ避けるべきである。ただし、現実的には不可避な面も多々あるため、上手に付き合うことが必要と言える。
ちなみに「down」なのは、クラスの継承関係において「サブクラス」が「スーパークラス」の「下」にあるためである。
参考サイト
// Sample.java
public class Sample
{
public static void main( String[] args )
{
// Integerクラスを作ります。
Integer integer = new Integer( 100 );
System.out.println( integer );
// 100
// 一度スーパークラスへ「アップキャスト」します。
// アップキャストは暗黙的にキャストされます。
Object object = integer;
System.out.println( object );
// 100
// そして、これを元のクラスに「ダウンキャスト」します。
// ダウンキャストは明示的にキャストする必要があります。
integer = (Integer)object;
System.out.println( integer );
// 100
System.out.println( integer instanceof Integer );
// true
// ダウンキャストは、サブクラスの型であれば
// どんな型でも可能なので、実際のインスタンスの型と
// 異なる型にキャストしてしまう可能性があります。
object = new Long( 200 );
System.out.println( object );
try
{
// インスタンスはLongクラスですが、
// わざと間違えてIntegerクラスに
// ダウンキャストします。
integer = (Integer)object;
}
catch( ClassCastException e )
{
e.printStackTrace();
// java.lang.ClassCastException
// at Sample.main(Sample.java:35)
// 型が異なるのでClassCastExceptionが
// 投げられました。
}
}
}
public class Sample
{
public static void main( String[] args )
{
// Integerクラスを作ります。
Integer integer = new Integer( 100 );
System.out.println( integer );
// 100
// 一度スーパークラスへ「アップキャスト」します。
// アップキャストは暗黙的にキャストされます。
Object object = integer;
System.out.println( object );
// 100
// そして、これを元のクラスに「ダウンキャスト」します。
// ダウンキャストは明示的にキャストする必要があります。
integer = (Integer)object;
System.out.println( integer );
// 100
System.out.println( integer instanceof Integer );
// true
// ダウンキャストは、サブクラスの型であれば
// どんな型でも可能なので、実際のインスタンスの型と
// 異なる型にキャストしてしまう可能性があります。
object = new Long( 200 );
System.out.println( object );
try
{
// インスタンスはLongクラスですが、
// わざと間違えてIntegerクラスに
// ダウンキャストします。
integer = (Integer)object;
}
catch( ClassCastException e )
{
e.printStackTrace();
// java.lang.ClassCastException
// at Sample.main(Sample.java:35)
// 型が異なるのでClassCastExceptionが
// 投げられました。
}
}
}
// Sample.java public class Sample { public static void main( String[] args ) { // Integerクラスを作ります。 Integer integer = new Integer( 100 ); System.out.println( integer ); // 100 // 一度スーパークラスへ「アップキャスト」します。 // アップキャストは暗黙的にキャストされます。 Object object = integer; System.out.println( object ); // 100 // そして、これを元のクラスに「ダウンキャスト」します。 // ダウンキャストは明示的にキャストする必要があります。 integer = (Integer)object; System.out.println( integer ); // 100 System.out.println( integer instanceof Integer ); // true // ダウンキャストは、サブクラスの型であれば // どんな型でも可能なので、実際のインスタンスの型と // 異なる型にキャストしてしまう可能性があります。 object = new Long( 200 ); System.out.println( object ); try { // インスタンスはLongクラスですが、 // わざと間違えてIntegerクラスに // ダウンキャストします。 integer = (Integer)object; } catch( ClassCastException e ) { e.printStackTrace(); // java.lang.ClassCastException // at Sample.main(Sample.java:35) // 型が異なるのでClassCastExceptionが // 投げられました。 } } }