10. クラスとオブジェクト

本サイトで紹介している商品・サービス等の外部リンクには、アフィリエイト広告が含まれる場合があります。

概要

Kotlin は、オブジェクト指向プログラミング (Object Oriented Programming, OOP) をサポートしています。
オブジェクト指向プログラミングにおいて重要な概念は、クラスとオブジェクトです。

まずは、クラストオブジェクトの概念およびオブジェクト指向プログラミングに関して記載しておきます。

クラスとオブジェクト

クラス (class) は、直訳すると 共通の性質を持つ部類とか種類 といった意味合いとなります。
オブジェクト (object) は、物、物体 といった意味合いです。

現実の世界からすると、存在している物体(オブジェクト)に対して、共通の性質やそれが共通してできることを見出して分類する(クラス分けする)といった形が多いかもしれません。

オブジェクト指向プログラミングにおいては、逆からの定義です。
クラスとして、そのクラスに属するオブジェクトに対して設定したい共通の変数(プロパティ、プロパティ変数) と共通の関数(メンバ関数、メソッド) を定義し、クラスの定義に基づいて構築、実体化させたもの(インスタンス化したもの) がオブジェクトとなります。クラスはオブジェクトの設計図という表現のドキュメントが多いと思います。

例えば、クラスとして 犬を表すクラス Dog を定義した場合、プロパティ変数として名前と(name と breed) , メンバ関数として 吠える(bark) を定義した例が以下です。
そのクラス Dog をインスタンス化したのが myDog で、具体的な犬を表すオブジェクトになります。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 犬を表すクラス
class Dog(val name: String, val breed: String) {
fun bark() {
println("ワンワン!")
}
}
fun main (){
// Dog クラスのインスタンス (オブジェクト) を作成
val myDog =Dog("ポチ", "柴犬")
// オブジェクトのプロパティにアクセス
println(myDog.name) // 出力: ポチ
// オブジェクトのメソッドを呼び出す
myDog.bark() // 出力: ワンワン!
}
// 犬を表すクラス class Dog(val name: String, val breed: String) { fun bark() { println("ワンワン!") } } fun main (){ // Dog クラスのインスタンス (オブジェクト) を作成 val myDog =Dog("ポチ", "柴犬") // オブジェクトのプロパティにアクセス println(myDog.name) // 出力: ポチ // オブジェクトのメソッドを呼び出す myDog.bark() // 出力: ワンワン! }
// 犬を表すクラス
class Dog(val name: String, val breed: String) {
    fun bark() {
        println("ワンワン!")
    }
}

fun main (){
// Dog クラスのインスタンス (オブジェクト) を作成
    val myDog =Dog("ポチ", "柴犬")

// オブジェクトのプロパティにアクセス
    println(myDog.name)  // 出力: ポチ

// オブジェクトのメソッドを呼び出す
    myDog.bark()  // 出力: ワンワン!
}

オブジェクト指向プログラミング

オブジェクト指向とは、システム全体をオブジェクトの集合としてとらえて、オブジェクトの組み合わせや関連性によってシステム設計をする考え方といえると思います。
オブジェクト指向の考え方に基づくプログラミング手法が、オブジェクト指向プログラミング(OOP)となります。

オブジェクト指向プログラミングの特徴

オブジェクト指向プログラミングの特徴として、以下の特徴が挙げられます。

  1. カプセル化
  2. 継承
  3. ポリモーフィズム

カプセル化

カプセル化 (Encapsulation) は、ユーザーに関係のないもの、必要のないもの、操作してほしくないものは見せないようにすることです。
オブジェクトの操作をメソッドを通じて行うようにして、オブジェクトの内部構造を隠蔽し、外部からの不正なアクセスを防ぐことができます。

以下の例では、Counter クラスの count プロパティは private で宣言されているため、外部から直接アクセスすることはできません。 代わりに、increment メソッドと getCount メソッドを通じて、カウントの値を増減したり、取得したりすることができます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Counter {
private var count = 0
fun increment() {
count++
}
fun getCount(): Int {
return count
}
}
fun main (){
val counter = Counter()
counter.increment()
println(counter.getCount()) // 出力: 1
}
class Counter { private var count = 0 fun increment() { count++ } fun getCount(): Int { return count } } fun main (){ val counter = Counter() counter.increment() println(counter.getCount()) // 出力: 1 }
class Counter {
    private var count = 0

    fun increment() {
        count++
    }

    fun getCount(): Int {
        return count
    }
}

fun main (){
    val counter = Counter()
    counter.increment()
    println(counter.getCount())  // 出力: 1
}

継承

継承 (Inheritance) とは、既存のクラス (親クラス) をもとに、新しいクラス (子クラス) を作成する仕組みです。
子クラスは、親クラスのプロパティやメソッドを継承し、さらに独自の機能を追加することができます。
これによりコードの再利用性を高めることができます

以下の例では、Dog クラスは Animal クラスを継承しています。そのため、Dog クラスは Animal クラスの name プロパティと eat メソッドを継承し、さらに独自の breed プロパティと bark メソッドを追加しています。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
open class Animal(val name: String) {
fun eat() {
println("$name が食べている")
}
}
class Dog(name: String, val breed: String) : Animal(name) {
fun bark() {
println("ワンワン!")
}
}
fun main (){
val myDog = Dog("ポチ", "柴犬")
println ("名前は ${myDog.name} です。犬種は ${myDog.breed} です。") // 名前は ポチ です。犬種は 柴犬 です。
myDog.eat() // 出力: ポチ が食べている
myDog.bark() // 出力: ワンワン!
}
open class Animal(val name: String) { fun eat() { println("$name が食べている") } } class Dog(name: String, val breed: String) : Animal(name) { fun bark() { println("ワンワン!") } } fun main (){ val myDog = Dog("ポチ", "柴犬") println ("名前は ${myDog.name} です。犬種は ${myDog.breed} です。") // 名前は ポチ です。犬種は 柴犬 です。 myDog.eat() // 出力: ポチ が食べている myDog.bark() // 出力: ワンワン! }
open class Animal(val name: String) {
    fun eat() {
        println("$name が食べている")
    }
}

class Dog(name: String, val breed: String) : Animal(name) {
    fun bark() {
        println("ワンワン!")
    }
}

fun main (){
    val myDog = Dog("ポチ", "柴犬")
    println ("名前は ${myDog.name} です。犬種は ${myDog.breed} です。")  // 名前は ポチ です。犬種は 柴犬 です。
    myDog.eat()  // 出力: ポチ が食べている
    myDog.bark()  // 出力: ワンワン!
}

ポリモーフィズム

ポリモーフィズム (Polymorphism) は、多様性、多態性などと訳されます。
同じ名前のメソッドが、 オブジェクトの種類によって異なる動作をすることを可能にする仕組みです。
これによりコードの柔軟性を高めることができます。

以下の例では、Animal クラス、Dog クラス、Cat クラスはそれぞれ makeSound メソッドを持っていますが、その実装は異なります。 animals リストには Dog オブジェクトと Cat オブジェクトが格納されており、for ループで各オブジェクトの makeSound メソッドを呼び出すと、オブジェクトの種類に応じて異なる音が鳴ります。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
open class Animal(val name: String) {
open fun makeSound() {
println("$name が鳴いている")
}
}
class Dog(name: String) : Animal(name) {
override fun makeSound() {
println("ワンワン!")
}
}
class Cat(name: String) : Animal(name) {
override fun makeSound() {
println("ニャー")
}
}
fun main () {
val animals = listOf(Dog("ポチ"), Cat("タマ"))
for (animal in animals) {
animal.makeSound()
}
}
// 出力:
// ワンワン!
// ニャー
open class Animal(val name: String) { open fun makeSound() { println("$name が鳴いている") } } class Dog(name: String) : Animal(name) { override fun makeSound() { println("ワンワン!") } } class Cat(name: String) : Animal(name) { override fun makeSound() { println("ニャー") } } fun main () { val animals = listOf(Dog("ポチ"), Cat("タマ")) for (animal in animals) { animal.makeSound() } } // 出力: // ワンワン! // ニャー
open class Animal(val name: String) {
    open fun makeSound() {
        println("$name が鳴いている")
    }
}

class Dog(name: String) : Animal(name) {
    override fun makeSound() {
        println("ワンワン!")
    }
}

class Cat(name: String) : Animal(name) {
    override fun makeSound() {
        println("ニャー")
    }
}

fun main () {
    val animals = listOf(Dog("ポチ"), Cat("タマ"))
    for (animal in animals) {
        animal.makeSound()
    }
}
// 出力:
// ワンワン!
// ニャー