次のようにAクラスがBクラスの親クラスだった場合、Aクラス用の変数にBクラスのインスタンスを
代入することができます。しかし、逆はエラーになります。犬は哺乳類ですが、哺乳類は犬ではないのと
同様です。
class A{
:
:
}
class B extends A{
:
:
}
class Test{
public static void main(String arg[]){
// これはOK
A a = new B();
// これはエラー
B b = new A();
}
}
|
これまで、StringVectorクラスを作ってきましたが、何もStringクラスに特化させる必要はなかったのです。
次のようにすれば、Stringクラス以外のクラスもベクターとして管理することができるのです。
JavaではすべてのクラスがObjectクラスの子クラスです。最初から用意されているStringクラスは
もちろん、これまで作ってきたStringVectorクラスや、SortableStringVectorクラスも実はObjectクラスを
継承しているのです。
したがって、下記のようにStringVectorクラスをObjectVectorクラスに書き換えたベクタークラスを
用いて、今までどおりStringVectorのように使うことができます。
class Test{
public static void main(String args[]){
ObjectVector vect = new ObjectVector();
vect.at(0, "HogeHoge");
vect.at(1, "HonyoHonyo");
System.out.println(vect.at(0));
System.out.println(vect.at(1));
}
}
// StringVectorのStringをObjectに変更したベクタークラス
public class ObjectVector{
////////////////////////////////////////////////////
// 管理情報
protected int m_size; // 配列サイズ
protected Object m_vector[]; // 配列
// コンストラクタ:引数あり
// ObjectVector オブジェクトが定義された時に自動的に呼び出される
public ObjectVector( int sz ){
// 配列サイズを保存する
m_size = sz ;
// 配列の実体(size個のint配列)を自由記憶上に割り当てる
m_vector = new Object[m_size] ;
}
// コンストラクタ:引数なし
// ObjectVector オブジェクトが定義された時に自動的に呼び出される
public ObjectVector( ){
// もう1つのコンストラクタを呼び出す
this(100);
}
// 代入
public void at( int n, Object value ){
if( n >= m_size || n < 0 ){
System.err.println("invalid index");
System.exit(1) ; // 異常終了する
}
m_vector[n] = value ;
}
// 取得
public Object at(int n){
if( n >= m_size || n < 0 ){
System.err.println("invalid index");
System.exit(1) ; // 異常終了する
}
return m_vector[n];
}
// 現在の配列サイズを獲得する
public int getLength(){
return m_size;
}
}
|
ところが、mainメソッドを下記のように書き換えるとコンパイルエラーが出てしまいます。
class Test{
public static void main(String args[]){
ObjectVector vect = new ObjectVector();
vect.at(0, "HogeHoge");
vect.at(1, "HonyoHonyo");
String str1 = vect.at(0);
String str2 = vect.at(1);
}
}
|
C:\java>javac Test.java
Test.java:7: Incompatible type for declaration. Explicit cast needed to convert
java.lang.Object to java.lang.String.
String str1 = vect.at(0);
^
Test.java:8: Incompatible type for declaration. Explicit cast needed to convert
java.lang.Object to java.lang.String.
String str2 = vect.at(1);
^
2 errors
C:\java>
|
これは、ObjectVectorクラスのatメソッドの戻り値がObjectクラスだからです。前述したように
StringクラスはObjectクラスの一種ですが、ObjectクラスはStringクラスの一種ではないため、
Objectクラスとして返された戻り値はStringクラスに代入できないのです。
しかし、プログラムを見ればお分かりのとおり、実際に戻ってくるのはStringクラスのインスタンスです。
この場合は、下記のようにキャストします。
class Test{
public static void main(String args[]){
ObjectVector vect = new ObjectVector();
vect.at(0, "HogeHoge");
vect.at(1, "HonyoHonyo");
String str1 = (String)vect.at(0);
String str2 = (String)vect.at(1);
}
}
|
C:\java>javac Test.java
C:\java>
|
では、Stringクラスのインスタンスが入っていないのに、Stringクラスにキャストしようとするとどうなるのでしょうか?
次の例では、StringクラスではなくTestクラスのインスタンスをObjectVectorに入れて、Stringクラスにキャストして
取り出そうとしています。
class Test{
public static void main(String args[]){
ObjectVector vect = new ObjectVector();
vect.at(0, "HogeHoge");
vect.at(1, new Test());
String str1 = (String)vect.at(0);
String str2 = (String)vect.at(1);
}
}
|
C:\java>javac Test.java
C:\java>java Test
Exception in thread "main" java.lang.ClassCastException: Test
at Test.main(Test.java:8)
C:\java>
|
文法的には間違っていないのでコンパイルは正常にできますが、実際に実行しようとした場合に
キャストできないとエラーになってしまいます。
このようなことにならないようにプログラマーは気をつけなければいけませんが、下記のように
instanceof演算子を用いて、ミスしても大丈夫なようにするべきです。
class Test{
public static void main(String args[]){
ObjectVector vect = new ObjectVector();
vect.at(0, "HogeHoge");
vect.at(1, new Test());
String str1 = null;
String str2 = null;
Object obj;
obj = vect.at(0);
if( obj instanceof String )
str1 = (String)obj;
obj = vect.at(1);
if( obj instanceof String )
str2 = (String)obj;
}
}
|
C:\java>javac Test.java
C:\java>java Test
C:\java>
|