【Kotlin】レッスン5-10:抽象クラスの構文と使い方を基礎から学ぼう

ながみえ

一つ前のページではクラスを拡張について学習しました。

今回は 抽象クラス について見ていきましょう。

Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:関数編
Lesson4:コレクション編
Lesson5:オブジェクト指向編

 ・Lesson5-1:クラスの基本を理解しよう
 ・Lesson5-2:プライマリコンストラクタを理解しよう
 ・Lesson5-3:セカンダリコンストラクタを理解しよう
 ・Lesson5-4:ふたつのコンストラクタを使いこなそう
 ・Lesson5-5:アクセス修飾子とカプセル化を理解しよう
 ・Lesson5-6:静的メンバとインスタンスメンバを理解しよう
 ・Lesson5-7:クラスの継承を理解しよう
 ・Lesson5-8:メソッドのオーバーライドを理解しよう
 ・Lesson5-9:クラスを拡張しよう
 ・Lesson5-10:抽象クラスを理解しよう ◁今回はココ
 ・Lesson5-11:インターフェースを理解しよう
 ・Lesson5-12:データクラスを理解しよう
 ・確認問題5-☆1:モンスター捕獲ゲームを作ろう
 ・確認問題5-☆2:マルバツゲームを作ろう
 ・確認問題5-☆3:石取りゲームを作ろう

<<前のページ

学習記事一覧

次のページ>>

抽象クラスとは?継承前提クラスの基本と使い方

抽象クラス は他のクラスが継承するための基盤となるクラス(親クラスとして使用される前提のクラス)です。

インスタンス化することはできず、別のクラスに継承させることで、各クラスに共通の設計を提供します。

抽象クラスを定義する基本構文と使い方

抽象クラスを定義するには、abstract修飾子 を使用します。

以下はKotlinでの抽象クラスの基本的な構文です。

abstract class 抽象クラス名 {		 // 抽象クラスの定義
    abstract val 抽象定数名: 型	 // 値を持たない抽象プロパティの宣言
    abstract fun 抽象メソッド名()	// 処理を持たない抽象メソッドの定義
}

例えば、犬クラスや猫クラスに継承されることを想定した、動物クラスを抽象クラスとして定義してみましょう。

abstract class Animal {			// 抽象クラスAnimalの定義
    abstract val name: String	// 値を持たない抽象定数nameの宣言
    abstract fun makeSound()	// 処理を持たない抽象メソッドmakeSoundの定義

    fun eat() {					// 通常のメソッドの定義可能
        println("$name is eating.")
    }
}

抽象プロパティ抽象メソッド は具体的な実装を持たないため、具象クラスで必ずオーバーライドする必要があります。

  • 抽象クラス:共通点だけをまとめた設計図として使われる未完成なクラス
  • 具象クラス:抽象クラスを継承するクラス
あわせて読みたい
【Kotlin】レッスン5-8:メソッドのオーバーライドの仕組みと使い方
【Kotlin】レッスン5-8:メソッドのオーバーライドの仕組みと使い方

    抽象クラスの活用コード例

    抽象クラスを活用した具体的なコード例を見てみましょう。

    abstract class Animal {			// 抽象クラスAnimalの定義
        abstract val name: String	// 値を持たない抽象定数nameの宣言
        abstract fun makeSound()	// 処理を持たない抽象メソッドmakeSoundの定義
        fun eat() {					// 通常のメソッドの定義可能
            println("$name is eating.")
        }
    }
    
    class Dog : Animal() {			// Animalクラスを継承するDogクラスの定義
        override val name = "Dog"	// 抽象プロパティをオーバーライド
        override fun makeSound() {	// 抽象メソッドをオーバーライド
            println("Woof!")
        }
    }
    
    class Cat : Animal() {			// Animalクラスを継承するCatクラスの定義
        override val name = "Cat"	// 抽象プロパティをオーバーライド
        override fun makeSound() {	// 抽象メソッドをオーバーライド
            println("Meow!")
        }
    }
    fun main() {
        val dog = Dog()		// インスタンス生成
        dog.makeSound()		// 抽象メソッドの呼び出し:Woof!
        dog.eat()			// 通常のメソッドの呼び出し:Dog is eating.
    
        val cat = Cat()		// インスタンス生成
        cat.makeSound()		// 抽象メソッドの呼び出し:Meow!
        cat.eat()			// 通常のメソッドの呼び出し:Cat is eating.
    }

    ここでDogCatAnimalクラスを継承し、それぞれのnameプロパティとmakeSoundメソッドを実装しています。

    このコードを実行すると以下のように出力されます。

    Woof!
    Dog is eating.
    Meow!
    Cat is eating.

    まとめ|抽象クラスの活用で広がるオブジェクト設計

    抽象クラスは、共通する性質や機能だけをまとめて宣言し、具体的な処理やデータは子クラスにまかせる“設計図”のような存在です。

    抽象プロパティや抽象メソッドを活用することで、「必ず実装してほしい内容」や「共通する処理」を明確にし、コードの再利用性や保守性を高めることができます。

    オブジェクト指向の基本である「継承」や「多態性」を実現するためにも、抽象クラスの考え方をぜひしっかり身につけておきましょう。

    練習問題|抽象クラスと継承を使って図書館システムを実装しよう

    図書館の書籍情報を管理するシステムを作成しましょう。

    この問題の要件

    以下の要件に従ってコードを完成させてください。

    • 書籍の情報(タイトルと著者)を保持する抽象クラス Book を定義すること。
    • Book クラスを継承した LibraryBook クラスを定義し、書籍情報を表示するメソッドを実装すること。
    • 複数の LibraryBook オブジェクトを管理する Library クラスを定義すること。
    • Library クラスには、書籍を追加するメソッド、すべての書籍情報を表示するメソッド、指定された著者の書籍を検索して表示するメソッドを実装すること。
    • メイン関数で Library クラスのインスタンスを作成し、複数の書籍を追加して、全書籍情報と特定の著者の書籍情報を表示すること。

    ただし、以下のような実行結果となること。

    書籍「吾輩は猫である」が追加されました。
    書籍「こころ」が追加されました。
    書籍「羅生門」が追加されました。
    すべての書籍情報:
    タイトル: 吾輩は猫である, 著者: 夏目漱石
    タイトル: こころ, 著者: 夏目漱石
    タイトル: 羅生門, 著者: 芥川龍之介
    著者「夏目漱石」の書籍情報:
    タイトル: 吾輩は猫である, 著者: 夏目漱石
    タイトル: こころ, 著者: 夏目漱石

    この問題を解くヒント

    1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

    Q
    ヒント1【コードの構成を見る】

    正解のコードは上から順に以下のような構成となっています。

    1:抽象クラスBookを定義
      □ 抽象プロパティtitleとauthorを定義
      □ 抽象メソッドdisplayInfoを定義
    2:クラスLibraryBookを定義
      □ クラスBookを継承
      □ 抽象メソッドdisplayInfoをオーバーライド
      □ □ 文字列テンプレートを使用してタイトルと著者を出力
    3:クラスLibraryを定義
      □ プライベートプロパティbooksをmutableListとして初期化
      □ 関数addBookを定義
      □ □ 書籍をリストbooksに追加
      □ □ 文字列テンプレートで書籍追加のメッセージを出力
      □ 関数displayAllBooksを定義
      □ □ 「すべての書籍情報:」と出力
      □ □ forループでリストbooks内のすべての書籍情報を表示
      □ 関数searchByAuthorを定義
      □ □ 文字列テンプレートで著者検索のメッセージを出力
      □ □ forループでリストbooks内の著者一致する書籍情報を表示
    4:メイン関数を定義
      □ クラスLibraryのインスタンスlibraryを作成
      □ クラスLibraryBookのインスタンスbook1, book2, book3を作成
      □ 関数addBookを使用して書籍をlibraryに追加
      □ 関数displayAllBooksを使用してすべての書籍情報を表示
      □ 関数searchByAuthorを使用して著者名「夏目漱石」の書籍情報を表示

    Q
    ヒント2【穴埋め問題にする】

    以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

    // 抽象クラス Book を定義
    abstract class Book(val title: String, val author: String) {
        // 抽象メソッド
        abstract fun displayInfo()
    }
    
    // Book クラスを継承した LibraryBook クラスを定義
    class LibraryBook(title: String, author: String) : Book(title, author) {
        // 抽象メソッドをオーバーライドして実装
        /*【穴埋め問題1】
        ここに抽象メソッド displayInfo をオーバーライドして、書籍のタイトルと著者を表示するコードを書いてください。
        */
    }
    
    // Library クラスを定義
    class Library {
        // 書籍リストを保持するプロパティ
        private val books: MutableList<LibraryBook> = mutableListOf()
    
        // 書籍を追加するメソッド
        fun addBook(book: LibraryBook) {
            books.add(book)
            println("書籍「${book.title}」が追加されました。")
        }
    
        // すべての書籍情報を表示するメソッド
        fun displayAllBooks() {
            println("すべての書籍情報:")
            /*【穴埋め問題2】
            ここにfor文を使って、すべての書籍の情報を表示するコードを書いてください。displayInfo メソッドを使用します。
            */
        }
    
        // 指定された著者の書籍を表示するメソッド
        /*【穴埋め問題3】
        ここに、著者名で書籍を検索し、その著者の書籍情報を表示するコードを書いてください。
        */
    }
    
    // メイン関数
    fun main() {
        // Library のインスタンスを作成
        val library = Library()
    
        // 書籍を追加
        val book1 = LibraryBook("吾輩は猫である", "夏目漱石")
        val book2 = LibraryBook("こころ", "夏目漱石")
        val book3 = LibraryBook("羅生門", "芥川龍之介")
    
        library.addBook(book1)
        library.addBook(book2)
        library.addBook(book3)
    
        // すべての書籍情報を表示
        library.displayAllBooks()
    
        // 特定の著者の書籍を検索
        library.searchByAuthor("夏目漱石")
    }

    このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

    この問題の解答と解説

    この問題の正解コードとその解説は以下の通りです。

    クリックして開いて確認してください。

    Q
    正解コード
    // 抽象クラス Book を定義
    abstract class Book(val title: String, val author: String) {
        // 抽象メソッド
        abstract fun displayInfo()
    }
    
    // Book クラスを継承した LibraryBook クラスを定義
    class LibraryBook(title: String, author: String) : Book(title, author) {
        // 抽象メソッドをオーバーライドして実装
        override fun displayInfo() {
            println("タイトル: $title, 著者: $author")
        }
    }
    
    // Library クラスを定義
    class Library {
        // 書籍リストを保持するプロパティ
        private val books: MutableList<LibraryBook> = mutableListOf()
    
        // 書籍を追加するメソッド
        fun addBook(book: LibraryBook) {
            books.add(book)
            println("書籍「${book.title}」が追加されました。")
        }
    
        // すべての書籍情報を表示するメソッド
        fun displayAllBooks() {
            println("すべての書籍情報:")
            for (book in books) {
                book.displayInfo()
            }
        }
    
        // 指定された著者の書籍を表示するメソッド
        fun searchByAuthor(author: String) {
            println("著者「$author」の書籍情報:")
            for (book in books) {
                if (book.author == author) {
                    book.displayInfo()
                }
            }
        }
    }
    
    // メイン関数
    fun main() {
        // Library のインスタンスを作成
        val library = Library()
    
        // 書籍を追加
        val book1 = LibraryBook("吾輩は猫である", "夏目漱石")
        val book2 = LibraryBook("こころ", "夏目漱石")
        val book3 = LibraryBook("羅生門", "芥川龍之介")
    
        library.addBook(book1)
        library.addBook(book2)
        library.addBook(book3)
    
        // すべての書籍情報を表示
        library.displayAllBooks()
    
        // 特定の著者の書籍を検索
        library.searchByAuthor("夏目漱石")
    }
    Q
    正解コードの解説

    コードをブロックごとに分割して解説します。

    抽象クラス Book

    // 抽象クラス Book を定義
    abstract class Book(val title: String, val author: String) {
        // 抽象メソッド
        abstract fun displayInfo()
    }
    • 抽象クラスabstract class キーワードを使って抽象クラスを定義します。抽象クラスはテンプレートとして使用され、具体的なクラスで継承されることを目的としています。
    • プロパティtitleauthor は書籍のタイトルと著者を表すプロパティです。
    • 抽象メソッドabstract fun displayInfo() は抽象メソッドです。この例ではdisplayInfo メソッドが具体的なクラスで実装される必要があります。

    クラス LibraryBook

    // Book クラスを継承した LibraryBook クラスを定義
    class LibraryBook(title: String, author: String) : Book(title, author) {
        // 抽象メソッドをオーバーライドして実装
        override fun displayInfo() {
            println("タイトル: $title, 著者: $author")
        }
    }
    • 継承class LibraryBook : Book(title, author)Book クラスを継承しています。これによりBook クラスのプロパティとメソッドを使用できます。
    • コンストラクタLibraryBook クラスのコンストラクタは親クラスである Book のコンストラクタを呼び出しています。
    • メソッドのオーバーライドoverride fun displayInfo()Book クラスの抽象メソッド displayInfo をオーバーライドして具体的に実装しています。このメソッドは書籍のタイトルと著者を表示します。

    クラス Library

    // Library クラスを定義
    class Library {
        // 書籍リストを保持するプロパティ
        private val books: MutableList<LibraryBook> = mutableListOf()
    
        // 書籍を追加するメソッド
        fun addBook(book: LibraryBook) {
            books.add(book)
            println("書籍「${book.title}」が追加されました。")
        }
    
        // すべての書籍情報を表示するメソッド
        fun displayAllBooks() {
            println("すべての書籍情報:")
            for (book in books) {
                book.displayInfo()
            }
        }
    
        // 指定された著者の書籍を表示するメソッド
        fun searchByAuthor(author: String) {
            println("著者「$author」の書籍情報:")
            for (book in books) {
                if (book.author == author) {
                    book.displayInfo()
                }
            }
        }
    }
    • プロパティbooksMutableList<LibraryBook> 型のプロパティで、追加された書籍を保持します。
    • メソッド addBook:このメソッドは LibraryBook オブジェクトを books リストに追加し、追加されたことを表示します。
    • メソッド displayAllBooks:このメソッドは books リストに含まれるすべての書籍情報を表示します。
    • メソッド searchByAuthor:このメソッドは指定された著者の書籍情報を検索し、該当する書籍を表示します。

    メイン関数 main

    // メイン関数
    fun main() {
        // Library のインスタンスを作成
        val library = Library()
    
        // 書籍を追加
        val book1 = LibraryBook("吾輩は猫である", "夏目漱石")
        val book2 = LibraryBook("こころ", "夏目漱石")
        val book3 = LibraryBook("羅生門", "芥川龍之介")
    
        library.addBook(book1)
        library.addBook(book2)
        library.addBook(book3)
    
        // すべての書籍情報を表示
        library.displayAllBooks()
    
        // 特定の著者の書籍を検索
        library.searchByAuthor("夏目漱石")
    }
    • インスタンスの作成Library クラスのインスタンス library を作成します。
    • 書籍の追加:3つの LibraryBook オブジェクトを作成し、それぞれの書籍を library に追加します。
    • 書籍情報の表示library.displayAllBooks() メソッドを呼び出して、すべての書籍情報を表示します。
    • 著者の書籍を検索library.searchByAuthor("夏目漱石") メソッドを呼び出して、特定の著者の書籍情報を表示します。
    Q
    サイト改善アンケート & ご指摘/ご質問

    本サイトでは、みなさまの学習をよりサポートできるサービスを目指しております。
    そのため、みなさまの「プログラミングを学習する理由」などを アンケート 形式でお伺いしています。

    また記事の内容に関する ご指摘ご質問 もお待ちしています。

    1.このサイトをどのように活用していますか?また、今後どのように活用したいですか?
    5.気になっているサービス・商品があれば教えてください。
    ※ 特定の記事に関する内容の場合は、記事番号(レッスン〇-〇)をご記入願います。

    <<前のページ

    学習記事一覧

    次のページ>>

    記事URLをコピーしました