この記事で学べる知識:抽象クラス
この記事の練習問題を解くために必要な知識:
基礎文法、制御構造、関数、コレクション(レッスン1~4)、クラスの定義と使用、プライマリコンストラクタ、セカンダリコンストラクタ、アクセス修飾子とカプセル化、クラスメンバとインスタンスメンバ、クラスの継承、メソッドのオーバーライド、クラスの拡張、抽象クラス、インターフェース、データクラス
<<前のページ | Kotlin記事一覧 |
次のページ>> |
Kotlinの文法「抽象クラス」とは
ここでは抽象クラスの意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。
抽象クラスは他のクラスが継承するための基盤となるクラス(親クラスとして使用される前提のクラス)です。
インスタンス化することはできず、具象クラス(具体的に実装されたクラス)がこのクラスを継承することで、共通の設計を提供します。
Kotlinではクラスにabstract
修飾子を付けて抽象クラスを定義します。
抽象クラスの基本構文
以下はKotlinでの抽象クラスの基本的な構文です。
abstract class Animal { // 抽象クラスの定義 abstract val name: String // 具体的な値を持たない抽象プロパティの宣言 abstract fun makeSound() // 具体的な処理を持たない抽象メソッドの定義 fun eat() { // 通常のメソッド println("$name is eating.") } }
abstract
修飾子:抽象プロパティや抽象メソッドにはabstract
を付けます。- 抽象プロパティとメソッドの特徴:具体的な実装を持たないため、具象クラスで必ずオーバーライドする必要があります。
抽象クラスと具象クラス
抽象クラスを継承する子クラスは「具象クラス」と呼ばれます。
以下は具体的な例です。
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!") } }
ここでDog
とCat
はAnimal
クラスを継承し、それぞれのname
プロパティとmakeSound
メソッドを実装しています。
fun main() { val dog = Dog() dog.makeSound() // Woof! dog.eat() // Dog is eating. val cat = Cat() cat.makeSound() // Meow! cat.eat() // Cat is eating. }
このコードを実行すると以下のように出力されます。
Woof! Dog is eating. Meow! Cat is eating.
抽象プロパティと抽象メソッド
抽象クラスは具体的な実装が存在しないプロパティやメソッドを定義できます。
- 抽象プロパティ:
name
のように値が決まっていない変数を具象クラスで実装します。 - 抽象メソッド:
makeSound
のように動作を具体的に具象クラスで実装します。
また共通の振る舞い(例:eat
メソッド)は抽象クラス内で通常のメソッドとして実装可能です。
まとめ
抽象クラスは共通のプロパティやメソッドを定義する基盤として役立ちます。
具象クラスは抽象クラスを継承し、具体的な振る舞いを実装します。
これによりコードの再利用性と拡張性が向上します。
抽象クラスの練習問題
図書館の書籍情報を管理するシステムを作成しましょう。
この問題の要件
以下の要件に従ってプログラムを作成してください。
- 書籍の情報(タイトルと著者)を保持する抽象クラス
Book
を定義すること。 Book
クラスを継承したLibraryBook
クラスを定義し、書籍情報を表示するメソッドを実装すること。- 複数の
LibraryBook
オブジェクトを管理するLibrary
クラスを定義すること。 Library
クラスには、書籍を追加するメソッド、すべての書籍情報を表示するメソッド、指定された著者の書籍を検索して表示するメソッドを実装すること。- メイン関数で
Library
クラスのインスタンスを作成し、複数の書籍を追加して、全書籍情報と特定の著者の書籍情報を表示すること。
ただし、以下のような実行結果となること。
----- ↓出力される結果の例↓ -----
書籍「吾輩は猫である」が追加されました。 書籍「こころ」が追加されました。 書籍「羅生門」が追加されました。 すべての書籍情報: タイトル: 吾輩は猫である, 著者: 夏目漱石 タイトル: こころ, 著者: 夏目漱石 タイトル: 羅生門, 著者: 芥川龍之介 著者「夏目漱石」の書籍情報: タイトル: 吾輩は猫である, 著者: 夏目漱石 タイトル: こころ, 著者: 夏目漱石
この問題を解くヒント
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を使用して著者名「夏目漱石」の書籍情報を表示
以下のコードをコピーし、コメントに従ってコードを完成させて下さい。
// 抽象クラス 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("夏目漱石") }
この問題の穴埋めコードは以上です。
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
練習問題の解答と解説
この問題の一つの正解例とそのコードの解説を以下に示します。
正解コードの例
例えば以下のようなプログラムが考えられます。
// 抽象クラス 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("夏目漱石") }
正解コードの解説
今回のコードでは抽象クラスを用いたクラス設計の基本的な使い方を学びます。
以下にコードをブロックごとに分けて解説します。
抽象クラス Book
// 抽象クラス Book を定義 abstract class Book(val title: String, val author: String) { // 抽象メソッド abstract fun displayInfo() }
- 抽象クラス:
abstract class
キーワードを使って抽象クラスを定義します。抽象クラスはテンプレートとして使用され、具体的なクラスで継承されることを目的としています。 - プロパティ:
title
とauthor
は書籍のタイトルと著者を表すプロパティです。 - 抽象メソッド:
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() } } } }
- プロパティ:
books
はMutableList<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("夏目漱石")
メソッドを呼び出して、特定の著者の書籍情報を表示します。
まとめ
今回のコードではKotlinの抽象クラスを使用して書籍情報を管理するシステムを構築しました。
抽象クラス Book
とその具体的な実装である LibraryBook
クラス、そして書籍を管理する Library
クラスを組み合わせて、柔軟で拡張可能なシステムを作成しました。
メイン関数では実際に書籍を追加し、情報を表示する処理を行っています。
この例を通じてKotlinのクラスと継承、メソッドのオーバーライドの基本を学習することができます。
<<前のページ |
Kotlin記事一覧 |
次のページ>> |
この記事への質問・コメント
この記事を作成するにあたりAIを活用しています。
問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。
Kotlinのテキスト&問題集トップへ戻る
トップページへ戻る