<概要>継承について学びます。コンストラクタの動作に刮目せよ!
●例題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) --
○解説
10. class NamedRectangle extends Rectangle{
Rectangle クラスを継承して新しいクラス NamedRectangle を宣言しています。
extends という予約語の前に継承するクラスを、後ろに継承されるクラスを書きます。
「extend」という動詞は「拡張する」という意味で、
「extends」の最後に付いている s は、三人称単数現在形の s です。
ここで、NamedRectangle を Rectangle のサブクラス、
また逆に、Rectangle を NamedRectangle のスーパークラスと呼びます。
スーパー( super )は英語で「より上の」、サブ( sub )は英語で「より下の」という意味です。
スーパークラスは一つしか指定できません。
Java言語はC++言語の多重継承を行うことが出来ないのです。
しかし、サブクラスは一つのスーパークラスからいくつでも作れます。
また、サブクラスのサブクラス……といくらでも多段にクラスを継承することが出来ます。
○補足
static メソッド(このプログラムでは main メソッド)内部から、
非 static メソッド(このプログラムでは setSize メソッド)に直接アクセスする手段はありません。
必ずインスタンスを必要とします。
しかし、非 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;
}
「ここ」という部分にスーパークラスの引数無しコンストラクタの呼び出しが自動的に挿入されるのです。
「自動的に挿入される一文」の具体的なプログラムは次の例題を参照して下さい。
★コンストラクタは継承されない?
「Java言語プログラミングレッスン/結城浩」には、「コンストラクタは継承されない」と書いてあります。
しかし、これは正確な表現でしょうか?
もし継承されていないのであれば、スーパークラスのコンストラクタを呼び出せるはずがありません。
なぜなら、スーパークラスのコンストラクタをサブクラスは持っていないことになるからです。
したがって、「(特殊な場合しか)アクセスできない」の方が適切な表現ではないでしょうか?
同様に、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++言語と一緒ですね。