見出し画像

【Javaお勉強日記】クラスの継承についてまとめる

クラスの継承とは

本棚管理アプリを作りたいとして、基本となる「Book」クラスを作ったとする。
でも、本って「一冊で完結するもの」「シリーズもの」「雑誌」って色々な種類がある。

・タイトル、出版社、ページ数……等は全ての種類の本に共通の情報
・雑誌に「著者名」は要らないけど、●年●月号、という情報は必須
・シリーズものにはシリーズ名と巻数が要る

って具合に、「ちょっと同じだけどちょっと違う」ものを取り扱うためのクラスを作りたいときに、まず基本になる「本」オブジェクトを作り、それを取り込んで、「ちょっと違う」所だけ追加した「雑誌」「漫画」「新書」……と、色々な種類のオブジェクトを作ることができる。これが「クラスの継承」。

その時、基本になるオブジェクトを「スーパークラス」、スーパークラスを継承して作ったクラスを「サブクラス」と呼ぶ。

あるクラスを継承したクラスの作り方

// Book.java
package books;
// スーパークラスとなるBookクラスを用意
public class Book{
    private String title;
    private String Publisher;
    
    public Book(String title, String publisher){
        this.title = title;
        this.publisher = publisher
    }
    public getTitle(){
        return this.title
    }
    // 以下getPublisher略

}

// Comic.java
package books;

// Bookクラスを継承したComicクラスを作る
public class Comic extends Book{
    // BookになくてComicに必要なフィールド変数を宣言する
    private String author;
    private String sireseTitle;
    private String sireseNumber;
    
    // コンストラクタの引数には、スーパークラスの持っているフィールド変数も取る
    public Comic(String title, String publisher, String author, String sireseTitle, String sireseNumber){
        // 真っ先に、スーパークラスのコンストラクタを呼ぶ(必須)
        super(title, publisher);
        
        // それから、自クラスのフィールド変数を初期化する
        this.author = author;
        this.sireseTitle = sireseTitle;
        this.sireseNumber = sireseNumber;
    }
    
    // 以下、getAuthorとかgetSireseTitle...略

}

・サブクラスの宣言時に extends スーパークラス名 を付けると、スーパークラスを継承できる。(特にimportとか書く必要はない)

・まず、スーパークラスになく、サブクラスに必要なフィールド変数を宣言する

・それから、コンストラクタを作る。

・コンストラクタの一番最初で、Suber()を使って、スーパークラスのコンストラクタを呼び出す(スーパークラス名()、ではないので注意。また、Suber()の実行がコンストラクタ内の一番最初でないとコンパイルエラーになる)

これで、Bookクラスを継承したComicクラスが完成。

Bookクラスを継承しているので、Bookクラスにあるフィールド変数とメソッド全てを内包している。

スーパークラスのprivateメンバにはアクセス出来ない

ところが、上記の例のBookクラスのフィールド変数、titleとかpublisherはアクセス修飾子がprivateになっている。

例えBookを継承したサブクラスであっても、Comicの中でthis.titleしようとしてもアクセスできない。

えー それはちょっと不便じゃないの~~?

そんなときにはprotected

アクセス修飾子にはprivateとpublicの他にもう一つ、protectedがある。

protectedは「同じパッケージの中からならアクセスできる」「違うパッケージからの場合、そのクラスのサブクラスからならアクセスできる」という修飾子。

もちろんpublicにすればサブクラスからでもアクセスできるけど、publicにしちゃうのはちょっと怖い。そんなときにはprotectedを使うと、ほどほどにアクセスを制限できる。

でもそれ「予想外の変更」起きちゃうのでは?

起きちゃうね。

なので、安心して使える設計にするなら、サブクラスの中からでもスーパークラスのフィールド変数使いたい時は、publicにしてあるgetter使った方が安心……

ただ、現実的にどうしても理想通りの運用が出来ない場合もあるので、そんなときはprotectedで対応しよう。

スーパークラスのメソッドの呼び出し方

// Comic.java
package books;
public class Comic extends Book{
    private String author;
    private String sireseTitle;
    private String sireseNumber;
    
    public Comic(String title, String publisher, String author, String sireseTitle, String sireseNumber){
        // コンストラクタ略
    }
    
    // 以下、getAuthorとかgetSireseTitle...も略
    
    public void testPrint(){
    
        // this.を使って呼ぶ
        System.out.println(this.getTitle())
        
        // super.で呼んだ方が可読性が高い
        System.out.println(super.getTitle())
        
        // なんならthis.もsuper.もなくても使えちゃう
        System.out.println(getTitle())
    }
}
・Bookクラスを継承しているので、インスタンス作れば「this」の中にgetTitleも入るから、「this.getTitle」で呼び出すことが出来る。
・ただ、厳密に言うとサブクラスで定義してるメソッドじゃないから、後から自分や仲間が「this?thisのどこ??」ってなりそうなので、「super.getTitle」で呼びだした方がより読みやすい。
・実は this. も super. も無くても動くんだけど、いよいよ「このメソッドどこから来た?」になるので、明示的に書きたい。

final修飾子が付いているクラスは継承できない

【Javaお勉強日記】イミュータブル(変更不能)なオブジェクトを作る|yucco|note

ここでまとめたみたいに、変更不能にするためにfinal修飾子を付けたクラスは継承できない。

Stringとかの重要なクラスは、変なサブクラス作られないように継承不可になっていたりする。

全てのクラスの基底クラスはObjectクラス

絶対に全てのクラスに必要なメソッド(例えばtoString()とか)が揃っている基底クラス。

なんの継承も宣言せずにクラスを作ると、自動的にObjectクラスのサブクラスとして生成される。普段そのことを意識する必要はそんなにないけど、「toString()メソッド作ってないのにtoString()できちゃう!」とかはこれが原因なので、あたまの片隅に入れておく。

継承周りはひとまずこれくらいで。

この記事が気に入ったらサポートをしてみませんか?