継承は,オブジェクト指向プログラミング(OOP)の基本の1つです.すでにあるクラスを用いて新しいクラスを作成したい場合があります.新しいクラスを最初から作成するのではなく,モデルとなるクラスを土台にして新しいクラスを記述できれば便利です.Javaでは,extendsキーワードを用いて継承を行います.継承の元になるクラスをスーパークラス(基本クラス)といい,新しいクラスをサブクラス(派生クラス)といいます.
継承(Inheritance)
is-a |
クラスXからクラスYを派生する記述法は,
class Y extends X
{ // 派生クラスに追加するメンバの宣言 } |
解答 Personクラスにメインメソッドを含んでいる場合.
class Person
{ private String name, nationality; public Person(String name, String nationality) { this.name = name; this.nationality = nationality; } public static void main(String[] args) { Person p = new Person("横田","日本"); System.out.println("名前は" + p.name); System.out.println("国籍は" + p.nationality); } } |
実行結果
解答 Personクラスにメインメソッドを含んでいない場合.
class Person
{ private String name, nationality; public Person(String name, String nationality) { this.name = name; this.nationality = nationality; } } public class PersonIni { public static void main(String[] args) { Person p = new Person("横田","日本"); System.out.println("名前は" + p.name); System.out.println("国籍は" + p.nationality); } } |
実行結果
スーパーコンストラクタの呼び出し
class Person
{
protected String name, nationality;
public Person(String name, String nationality)
{
this.name = name;
this.nationality = nationality;
}
}
class Student extends Person
{
protected String id;
protected double gpa;
public Student(String id, double gpa)
{
super("横田","日本");// スーパーコンストラクタの呼び出し
this.id = id;
this.gpa = gpa;
}
}
public class StudentExtPerson
{
public static void main(String[] args)
{
Student st = new Student("600813902",3.85);
System.out.println("名前は" + st.name);
System.out.println("国籍は" + st.nationality);
System.out.println("学生番号は" + st.id);
System.out.println("gpaは" + st.gpa);
}
}
実行結果
メンバへのアクセス
privateメンバはクラスの中からだけアクセス可能です.
protectedメンバはクラス中からとその派生クラスからもアクセス可能です.
publicメンバはファイル内のどこからでもアクセス可能です.
一般に,protectedはそのクラスの派生クラスを定義する可能性があるときにprivateの代わりに用います. 派生クラスはその基本クラスのpublicおよびprotectedの全てのメンバを継承します.つまり,派生クラスから見ると,基本クラス(スーパークラス)のpublicおよびprotectedのメンバは,あたかも派生クラスで宣言されたようになります.例えば,クラスXと派生クラスYが
class X
{ public int a; protected int b; private int c; } class Y extends X { public int d; } で定義され,オブジェクトxとyが X x = new X(); Y y = new Y(); |
クラスXのpublicメンバaはYのpublicメンバとして継承され,クラスXのprotectedメンバbはYのprotectedメンバとして継承されますが,クラスXのprivateメンバcはクラスYに継承されません.
継承されたメンバのオーバーライド(Overriding Inherited Members)
Xが基本クラス(スーパークラス)で,YがXのサブクラス(派生クラス)のとき,YのオブジェクトはXの全てのpublicまたはprotectedメンバ変数およびメンバ関数を継承します.例えば,上の例題のPersonクラスのフィールド変数nameなどです.
ところが,ときには継承されたメンバを派生クラスに合わせた形に定義したいときがあります.例えば,nameがPersonクラスのフィールド変数で,StudentがPersonクラスの派生クラスのとき,nameというメンバ変数をStudentクラスに新たに定義することができます.このとき,Studentで定義されたフィールド変数nameはPersonクラスのフィールド変数nameに対し 優位(dominate)であるといいます. ここで,クラスStudentのオブジェクトsによるnameの参照s.nameはPersonクラスで定義されたnameではなく,Studentで定義されたフィールド変数nameをアクセスします.Personクラスのフィールド変数nameをアクセスするときにはsuperキーワードを用いて,super.nameとします.つまり,Studentクラスオブジェクトは基本クラス(スーパークラス)とサブクラスの両方のメンバにアクセスできます.
解答 StudentクラスオブジェクトsがStudentクラスのメンバ変数nameにアクセスするには,s.nameでよい.また,Personクラスのメンバ変数にアクセスするには,super.nameのように,superを用いる.
class Person
{
protected String name, nationality;
public Person(String name, String nationality)
{
this.name = name;
this.nationality = nationality;
}
}
class Student extends Person
{
protected String id;
protected double gpa;
protected String name;
protected String nameP;
public Student(String name, String id, double gpa)
{
super("横田","日本");
nameP = super.name;
this.name = name;
this.id = id;
this.gpa = gpa;
}
}
public class FieldOverride
{
public static void main(String[] args)
{
Student st = new Student("Yokota","600813902",3.85);
System.out.println("名前は" + st.nameP);
System.out.println("ローマ字で書くと" + st.name);
}
}
実行結果
メソッドに対しても同じことがいえます.printName()メソッドがPersonクラスで定義され,さらにStudentクラスでも定義されたならば,Studentクラスのオブジェクトsによる呼び出しs.printName()はStudentで定義されたprintName()メソッドを呼び出します.Personクラスで定義されたprintName()メソッドを呼び出すには,キーワードsuperを用いて,super.printName()とします.このとき, メソッドs.printName()はprintName()メソッドをオーバーライド(override)するといいます.
printName()メソッドを含むPersonクラスとその派生クラスStudentクラスを用い,Studentクラスオブジェクトsを用意し,s.printName()とsuper.printName()を比較しなさい. |
派生クラスから基本クラスのメンバへのアクセス
すでに説明しましたように,privateとprotectedの違いは,派生クラスからprotectedメンバはアクセスできますがprivateメンバはできないところです.では,いつメンバをprivateにしたらよいのでしょうか.その答えは,principle of information hiding(情報隠蔽原則)で説明されます.つまり,最初はアクセスを制限し,後で変更します.もし,将来,メンバ変数の変更を考えているのなら,privateで宣言しておくことにより,派生クラスでの変更を必要のないものにします.派生クラスはprivateデータメンバと独立です.
例えば,Personクラスのオブジェクトである人物が大卒かどうか知る必要があるとします.このとき,フィールド変数collegeをprotectedで追加することができますが,後で,もっと詳しい学歴の情報を付け加えるかもしれないので,この段階ではprivateメンバ変数にし,派生クラスからのアクセスを制限するほうがよいでしょう.
1. 合成と継承の違いは何か
2. protecedとprivateメンバの違いは何か
3. 仮想関数とは何か
4. 抽象基本クラスとは何か
5. 多相とは何か
6. 具象導出クラスとは何か
7. 静的結合と動的結合の違いは何か
1. 次の定義はどこが間違っているか
class X
{
protected:
int a;
};
class Y : public X
{
public:
void set(X x, int c) {x.a = c;}
};
2. 次のクラス階層を実装せよ.