<本章の目的>継承を習得する。コンストラクタの動作に刮目せよ!
●例題12-1 クラスを継承して下さい。
○プログラム
class Rectangle{
int width;
int height;
void setSize(int width,int height){
this.width=width;
this.height=height;
}
}
class NamedRectangle extends Rectangle{
public static void main(String[] args){
NamedRectangle nr=new NamedRectangle();
nr.setSize(123,45);
System.out.println(nr.width);
System.out.println(nr.height);
}
}
○実行結果
D:\atsushi\Java\List12-1&2>java NamedRectangle
123
45
-- Press any key to exit (Input "c" to continue) --
○解説
class NamedRectangle extends Rectangle
Rectangle クラスを継承して新しいクラス NamedRectangle を宣言しています。
extend という動詞は「拡張する」という意味で、
extends の最後に付いている s は、三人称単数現在形の s です。
ここで、NamedRectangle を Rectangle のサブクラス、
また逆に、Rectangle を NamedRectangle のスーパークラスと呼びます。
スーパー( super )は英語で「より上の」、サブ( sub )は英語で「より下の」という意味です。
スーパークラスは一つしか指定できません。
しかし、サブクラスは一つのスーパークラスからいくつでも作れます。
また、サブクラスのサブクラス……といくらでも多段にクラスを継承することが出来ます。
○補足
static メソッド内部から、非 static メソッドに直接アクセスする手段はありません。
必ずインスタンスを必要とします。
しかし、非 static メソッド内部からであれば、非 static メソッドに直接アクセスできます。
○補足2
Object クラスはすべてのクラスの共通の祖先です。
つまり、Object クラスは、すべてのクラスの中で唯一、スーパークラスを持たないクラスになります。
スーパークラスを指定しないで宣言したクラスも、
自動的に Object クラスをスーパークラスとして持つクラスになります。
class Rectangle{
……
}
は、
class Rectangle extends Object{
……
}
と同じ意味です。
●例題12-2 スーパークラスのコンストラクタを明示的に呼び出していない場合の動作を確認して下さい。
○プログラム
class Rectangle{
int width;
int height;
Rectangle(){
width=640;
height=480;
}
Rectangle(int width,int height){
this.width=width;
this.height=height;
}
}
class NamedRectangle extends Rectangle{
String name;
NamedRectangle(){
name="NO NAME";
}
NamedRectangle(String name){
this.name=name;
}
public static void main(String[] args){
NamedRectangle nr=new NamedRectangle();
NamedRectangle ns=new NamedRectangle("ATHENS");
System.out.println(nr.width);
System.out.println(nr.height);
System.out.println(nr.name);
System.out.println(ns.width);
System.out.println(ns.height);
System.out.println(ns.name);
}
}
○実行結果
D:\atsushi\Java\List12-5>java NamedRectangle
640
480
NO NAME
640
480
ATHENS
-- Press any key to exit (Input "c" to continue) --
○解説
スーパークラスのコンストラクタを明示的に呼び出していない場合、
サブクラスのコンストラクタの最初で、スーパークラスの引数無しコンストラクタが自動的に呼び出されます。
NamedRectangle(){
//ここ
name="NO NAME";
}
NamedRectangle(String name){
//ここ
this.name=name;
}
「ここ」という部分にスーパークラスの引数無しコンストラクタの呼び出しが自動的に挿入されるのです。
「自動的に挿入される一文」の具体的なプログラムは次の例題を参照して下さい。
★コンストラクタは継承されない?
教科書には、「コンストラクタは継承されない」と書いてあります。
しかし、これは正確な表現でしょうか?
もし継承されていないのであれば、スーパークラスのコンストラクタを呼び出せるはずがありません。
なぜなら、スーパークラスのコンストラクタをサブクラスは持っていないことになるからです。
したがって、「(特殊な場合しか)アクセスできない」の方が適切な表現ではないでしょうか?
同様に、prirave フィールド、private メソッドも継承されないと書いてありますが、
これは明らかに「(直接)アクセスできない」の間違いですね。
public メソッドを辿れば、private フィールド、private メソッドにアクセスできるんですから。
●例題12-3 スーパークラスのコンストラクタを明示的に呼び出して下さい。
○プログラム
class Rectangle{
int width;
int height;
Rectangle(){
width=640;
height=480;
}
Rectangle(int width,int height){
this.width=width;
this.height=height;
}
}
class NamedRectangle extends Rectangle{
String name;
NamedRectangle(){
this("NO NAME");
}
NamedRectangle(String name){
super(200,32);
this.name=name;
}
public static void main(String[] args){
NamedRectangle nr=new NamedRectangle();
NamedRectangle ns=new NamedRectangle("ATHENS");
System.out.println(nr.width);
System.out.println(nr.height);
System.out.println(nr.name);
System.out.println(ns.width);
System.out.println(ns.height);
System.out.println(ns.name);
}
}
○実行結果
D:\atsushi\Java\List12-7>java NamedRectangle
200
32
NO NAME
200
32
ATHENS
-- Press any key to exit (Input "c" to continue) --
○解説
super() は、スーパークラスのコンストラクタの呼び出しを表しています。
super() なら Rectangle() が、super(200,32) なら Rectangle(int width,int
height) が呼び出されます。
this() は、自分のコンストラクタの呼び出しを表しています。
this() や super() はコンストラクタの最初に書かなければなりません。
そうじゃない場合、コンパイルエラーになります。
引数を持たない super() は、スーパークラスの引数無しコンストラクタを表しています。
スーパークラスの明示的な呼び出しを省略した場合に
「自動的に挿入される一文」とは、つまりコレのことです。
したがって、書いても書かなくても動作は同じです。
スーパークラスのコンストラクタが一つも宣言されていない場合、
デフォルトコンストラクタが呼び出されます。
○補足
super …… スーパークラスのインスタンスを指すポインタ
super() …… スーパークラスのコンストラクタ
this …… 自分のクラスのインスタンスを指すポインタ
this() …… 自分のクラスのコンストラクタ
●例題12-4 スーパークラスとサブクラスのコンストラクタの動作を確認して下さい。
○プログラム
class A{
A(){
System.out.println("1:A()");
}
A(int x){
System.out.println("2:A(int x)");
}
}
class B extends A{
B(){
System.out.println("3:B()");
}
B(int x){
System.out.println("4:B(int x)");
}
B(String s){
super(789);
System.out.println("5:B(String s)");
}
public static void main(String[] args){
System.out.println("-----");
new A();
System.out.println("-----");
new B();
System.out.println("-----");
new A(123);
System.out.println("-----");
new B(456);
System.out.println("-----");
new B("test");
System.out.println("-----");
}
}
○実行結果
D:\atsushi\Java\List12-16>java B
-----
1:A()
-----
1:A()
3:B()
-----
2:A(int x)
-----
1:A()
4:B(int x)
-----
2:A(int x)
5:B(String s)
-----
-- Press any key to exit (Input "c" to continue) --
○解説
どのコンストラクタが呼び出されているか、
どういう順番で呼び出されているかに注目して下さい。
必ずスーパークラスのコンストラクタの方が先に呼び出されるのは
C++言語と一緒ですね。