継承におけるコンストラクタの取り扱いについて詳しく見ていく前に、コンストラクタはどのようなものであったか復習してみる。
new
キーワードと一緒に呼び出すことで、メモリ上にインスタンスの実体をつくり、インスタンスの初期設定を行うという役割を持ったもの
上記に加え、継承におけるコンストラクタは以下のようになる。
では、実際にプログラムを用いて順に説明を行う。
前回の継承のプログラムを用いて、説明を行う。
これが前回のプログラムである。public class Shape{ //図形の色を入れるためのフィールド private String color; //図形の色をセットするためのメソッド public void setColor( String color ){ this.color = color; } //図形の色を返すメソッド public String getColor(){ return color; } }//長方形クラス(Rectangle.java):
public class Rectangle extends Shape{ //図形の名前(Rectangle)を格納したクラス変数 public static final String NAME = "Rectangle"; //コンストラクタ public Rectangle( String color ){ setColor( color ); } }//円クラス(Circle.java):
public class Circle extends Shape{ //図形の名前(Circle)を格納したクラス変数 public static final String NAME = "Circle"; //コンストラクタ public Circle( String color ){ setColor( color ); } }//ShapeTestクラス(ShapeTest.java):
public class ShapeTest{ public static void main( String args[] ){ //インスタンスを生成 Rectangle shape1 = new Rectangle( "Red" ); Circle shape2 = new Circle( "Yellow" ); //各インスタンスの色の表示 System.out.println( shape1.name + "'s color : " + shape1.getColor() ); System.out.println( shape2.name + "'s color : " + shape2.getColor() ); } }
RectangleクラスとCircleクラスのコンストラクタに同じ部分があるので、スーパークラスであるShapeクラスにまとめてコンストラクタを定義してみる。
public class Shape{ //図形の色を入れるためのフィールド private String color; //コンストラクタ public Shape( String color ){ setColor( color ); } //図形の色をセットするためのメソッド public void setColor( String color ){ this.color = color; } //図形の色を返すメソッド public String getColor(){ return color; } }//長方形クラス(Rectangle.java):
public class Rectangle extends Shape{ //図形の名前(Rectangle)を格納したクラス変数 public static final String NAME = "Rectangle";//円クラス(Circle.java)://コンストラクタpublic Shape( String color ){setColor( color );}}
public class Circle extends Shape{ //図形の名前(Circle)を格納したクラス変数 public static final String NAME = "Circle";//ShapeTestクラス(ShapeTest.java)://コンストラクタpublic Shape( String color ){setColor( color );}}
public class ShapeTest{ public static void main( String args[] ){ //インスタンスを生成 Rectangle shape1 = new Rectangle( "Red" ); Circle shape2 = new Circle( "Yellow" ); //各インスタンスの色の表示 System.out.println( shape1.name + "'s color : " + shape1.getColor() ); System.out.println( shape2.name + "'s color : " + shape2.getColor() ); } }
このソースをコンパイルすると、以下のようなコンパイルエラーが起こる。
[eiko@eiko Java]$ javac ShapeTest.java ShapeTest.java:25: Shape の Shape(java.lang.String) は () に適用できません。 class Rectangle extends Shape{ ^ ShapeTest.java:33: Shape の Shape(java.lang.String) は () に適用できません。 class Circle extends Shape{ ^ ShapeTest.java:45: シンボルを解決できません。 シンボル: コンストラクタ Rectangle (java.lang.String) 場所 : Rectangle の クラス Rectangle shape1 = new Rectangle( "Red" ); ^ ShapeTest.java:46: シンボルを解決できません。 シンボル: コンストラクタ Circle (java.lang.String) 場所 : Circle の クラス Circle shape2 = new Circle( "Yellow" ); ^ エラー 4 個これは、継承によってスーパークラスのコンストラクタはサブクラスに継承されないからである。
上のソースでコンストラクタは継承されないので、継承を行ってもサブクラスでコンストラクタを定義する必要があることがわかった。
そこで、下のソースではスーパークラスだけでなく、サブクラスにもコンストラクタの定義を行った。
public class Shape{ //図形の色を入れるためのフィールド private String color; //コンストラクタ public Shape( String color ){ setColor( color ); } //図形の色をセットするためのメソッド public void setColor( String color ){ this.color = color; } //図形の色を返すメソッド public String getColor(){ return color; } }//長方形クラス(Rectangle.java):
public class Rectangle extends Shape{ //図形の名前(Rectangle)を格納したクラス変数 public static final String NAME = "Rectangle"; //コンストラクタ public Rectangle( String color ){ setColor( color ); } }//円クラス(Circle.java):
public class Circle extends Shape{ //図形の名前(Circle)を格納したクラス変数 public static final String NAME = "Circle"; //コンストラクタ public Circle( String color ){ setColor( color ); } }//ShapeTestクラス(ShapeTest.java):
public class ShapeTest{ public static void main( String args[] ){ //インスタンスを生成 Rectangle shape1 = new Rectangle( "Red" ); Circle shape2 = new Circle( "Yellow" ); //各インスタンスの色の表示 System.out.println( shape1.name + "'s color : " + shape1.getColor() ); System.out.println( shape2.name + "'s color : " + shape2.getColor() ); } }
このソースをコンパイルすると、今度は以下のように別の部分でコンパイルエラーが起こる。
[eiko@eiko Java]$ javac ShapeTest.java ShapeTest.java:31: Shape の Shape(java.lang.String) は () に適用できません。 public Rectangle( String color ){ ^ ShapeTest.java:45: Shape の Shape(java.lang.String) は () に適用できません。 public Circle( String color ){ ^ エラー 2 個
継承を行った場合、コンストラクタの定義の最初でスーパークラスのコンストラクタ又は自分のクラスの別のコンストラクタを呼び出さない場合、暗黙的にスーパークラスの引数なしコンストラクタを呼び出す形になるという話をはじめにした。
このソースの場合、スーパークラスで引数つきのコンストラクタを定義した時点で、デフォルトのコンストラクタが作られなくなるため、スーパークラスに引数なしのコンストラクタは存在しない。
しかし、サブクラスのコンストラクタが暗黙的にスーパークラスの引数なしコンストラクタを呼び出しているため、コンパイルエラーが起こっているのである。
一番簡単なエラー回避の方法として、スーパークラスShapeに引数なしのコンストラクタを以下のように定義する方法がある。
これにより、スーパークラスShapeで引数つきコンストラクタを定義したことによって、デフォルトコンストラクタが作られなくなった分を補うことができる。
public class Shape{ //図形の色を入れるためのフィールド private String color; //コンストラクタ(引数なし) public Shape(){ } //コンストラクタ(引数あり) public Shape( String color ){ setColor( color ); } //図形の色をセットするためのメソッド public void setColor( String color ){ this.color = color; } //図形の色を返すメソッド public String getColor(){ return color; } }//長方形クラス(Rectangle.java):
public class Rectangle extends Shape{ //図形の名前(Rectangle)を格納したクラス変数 public static final String NAME = "Rectangle"; //コンストラクタ public Rectangle( String color ){ setColor( color ); } }//円クラス(Circle.java):
public class Circle extends Shape{ //図形の名前(Circle)を格納したクラス変数 public static final String NAME = "Circle"; //コンストラクタ public Circle( String color ){ setColor( color ); } }//ShapeTestクラス(ShapeTest.java):
public class ShapeTest{ public static void main( String args[] ){ //インスタンスを生成 Rectangle shape1 = new Rectangle( "Red" ); Circle shape2 = new Circle( "Yellow" ); //各インスタンスの色の表示 System.out.println( shape1.name + "'s color : " + shape1.getColor() ); System.out.println( shape2.name + "'s color : " + shape2.getColor() ); } }
public class Shape{ //図形の色を入れるためのフィールド private String color; //コンストラクタ(引数あり) public Shape( String color ){ this.color = color; }//長方形クラス(Rectangle.java)://図形の色をセットするためのメソッドpublic void setColor( String color ){this.color = color;}//図形の色を返すメソッド public String getColor(){ return color; } }
public class Rectangle extends Shape{ //図形の名前(Rectangle)を格納したクラス変数 public static final String NAME = "Rectangle"; //コンストラクタ public Rectangle( String color ){ super( color ); } }//円クラス(Circle.java):
public class Circle extends Shape{ //図形の名前(Circle)を格納したクラス変数 public static final String NAME = "Circle"; //コンストラクタ public Circle( String color ){ super( color ); } }//ShapeTestクラス(ShapeTest.java):
public class ShapeTest{ public static void main( String args[] ){ //インスタンスを生成 Rectangle shape1 = new Rectangle( "Red" ); Circle shape2 = new Circle( "Yellow" ); //各インスタンスの色の表示 System.out.println( shape1.name + "'s color : " + shape1.getColor() ); System.out.println( shape2.name + "'s color : " + shape2.getColor() ); } }