クラスの継承
superの使い方
スーパークラスのメンバを参照する
super
目次
1. super の使い方
super() がスーパークラスのコンストラクタを示すことは、すでに紹介させて頂いた通りですが、
super はコンストラクタ以外にも、スーパークラスのメンバを表すことができます。
super の使い方
| super() | スーパークラスのコンストラクタ |
| super.変数名 | スーパークラスの変数 |
| super.メソッド名() | スーパークラスのメソッド |
2. スーパークラスのメソッド
重要
super.メソッド名() は、オーバーライドされる前のメソッド
//Animal_01.java
public class Animal_01{
protected static String group = "生き物です。";
protected String name;
public Animal_01(){
this("無名");
}
public Animal_01(String name){
this.name = name;
}
public static void printGroup(){
System.out.println(group);
}
public void printName(){
System.out.println(name + "だぞ! ガオー!");
}
}
この書き方は
実践でも使える。
//Dog_11.java
public class Dog_11 extends Animal_01{
public Dog_11(String name){
super(name);
}
@Override
public void printName(){
System.out.println("ジャジャーン!");
super.printName();
System.out.println("なんちゃって。");
}
}
オーバーライドした
printNameメソッドの中で、
super.printName()?
そう。
スーパークラスのメソッドに
処理を付け足したいとき
便利だ。
重要
super.メソッド名() は、メソッドの先頭である必要はありません。
super.メソッド名() は、異なるメソッドの中でも使用できます。
//Driver_11.java
public class Driver_11{
public static void main(String[] args){
Dog_11 dog = new Dog_11("フレンダー");
dog.printName();
}
}
Animal_01.java、
Dog_11.java、
Driver_11.java、の3つのファイルを
wsフォルダに保存して実行します。
コマンドライン
>cd ws
ws>javac -encoding UTF-8 Driver_11.java
ws>java Driver_11
ジャジャーン!
フレンダーだぞ! ガオー! ← super.printName()
なんちゃって。
3. スーパークラスの変数
重要
super.変数 と、this.変数 は共存できる
できるだけ避けてください。
サブクラスで、スーパークラスの変数と同名の変数を宣言すると、
サブクラスでは、super.変数 と、this.変数 が
共存するようになります。
クラスを指定しないで変数を使うと、サブクラスの変数 this.変数 が優先されます。
これってさぁ、
「ローカル変数とクラス変数を
同じ名前で宣言するな」って話と同じ話?
同じ話。
4. 実験
理解を深めるために、ちょっと実験してみましょう。
Dog_12クラスは、Animal_01クラスのサブクラスです。
Dog_12クラスで、Animal_01クラスと同名の変数「name」を宣言しました。
Dog_12クラスでは、this.name と super.name が共存します。
これは実験のためのサンプルだ。
マネしちゃダメなやつね。
//Dog_12.java
public class Dog_12 extends Animal_01{
protected String name; //スーパークラスと同名の変数
public Dog_12(String name){
super(name);
}
public void printSuper(){
System.out.println("this.name: " + this.name);
System.out.println("super.name: " + super.name);
}
}
↓↓↓ 以下のようなイメージ。↓↓↓
継承って
こうゆうことか!
Dog_12 のイメージ
//Dog_12.java
public class Dog_12 extends Animal_01{
protected String name;
//super.name; ←見えていないけどいる。
public Dog_12(String name){
super(name); //super なので、super.name に代入。
}
// ↓見えていないけどいる。
@Override
public void printName(){
super.printName(); //super なので、super.name を参照。
}
public void printSuper(){
System.out.println("this.name: " + this.name);
System.out.println("super.name: " + super.name);
}
}
以下のように、Dog_12クラスをインスタンス化しました。
引数「"フレンダー"」が代入されるのはどこでしょう?
//Driver_12.java
public class Driver_12{
public static void main(String[] args){
Dog_12 dog = new Dog_12("フレンダー");
dog.printName();
System.out.println("-----------------------");
dog.printSuper();
}
}
コマンドライン
>cd ws
ws>javac -encoding UTF-8 Driver_12.java
ws>java Driver_12
フレンダーだぞ! ガオー!
-----------------------
this.name: null
super.name: フレンダー
「"フレンダー"」は、super(name); によって、super.name の方に代入されました。
printName()は、スーパークラスから継承されたので super.name を参照しています。
「フレンダーだぞ! ガオー!」は、正しく表示されています。
this.name は使われていません。
今度は printName() をオーバーライドして、変数 name を参照しています。
//Dog_13.java
public class Dog_13 extends Animal_01{
protected String name; //スーパークラスと同名の変数
public Dog_13(String name){
super(name);
}
@Override
public void printName(){
System.out.println(name + "だワン!"); //この name は this.name
}
public void printSuper(){
System.out.println("this.name: " + this.name);
System.out.println("super.name: " + super.name);
}
}
//Driver_13.java
public class Driver_13{
public static void main(String[] args){
Dog_13 dog = new Dog_13("フレンダー");
dog.printName();
System.out.println("-----------------------");
dog.printSuper();
}
}
コマンドライン
>cd ws
ws>javac -encoding UTF-8 Driver_13.java
ws>java Driver_13
nullだワン!
-----------------------
this.name: null
super.name: フレンダー
「"フレンダー"」は、Dog_12クラスと同様に、super(name); によって、
super.name に代入されました。
そして、サブクラスの printName()で参照しているのは、this.name です。
this.name は、初期値のままなので、
「nullだワン!」になってしまいました。
サブクラスで、うっかり同名の変数を宣言すると面倒です。
避けた方が無難でしょう。
お疲れ様でした。