ことり「それじゃ今回からは、オブジェクト指向言語Kotlinの中心になるクラスについて説明していきます」
凛「そもそもクラスって何?」
ことり「実装の上では、型だと考えればいいかな。今まで出てきたのも、String
クラスとか、Int
クラスとか、Array
クラスとか」
凛「実装の上では、かあ」
ことり「モデリングとか設計の話は、もう少し先でもいいと思うよ」
ことり「他の言語で出てきたようなサンプルコードを出しますね」
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
fun main(args: Array<String>) { var honoka = SchoolIdol("honoka", SchoolIdol.Profile("いちご", 78, 58, 82)) honoka.sing() honoka.dance() println(honoka.profile.favorite) var umi = SchoolIdol("umi", "Otonokizaka High.", SchoolIdol.Profile("ほむまん", 76, 58, 80)) } class SchoolIdol(name: String, profile: Profile) { var name: String var school: String var profile: Profile init { this.name = name this.school = "" this.profile = profile } constructor (name: String, school: String, profile: Profile) : this(name, profile) { this.school = school } fun sing() { println("${this.name} singing!!") } fun dance() { println("${this.name} dancing!!") } class Profile(favorite: String, b: Int, w: Int, h: Int) { var favorite: String = favorite var threeSize: Array<Int> = arrayOf(b, w, h) } } |
honoka singing!!
honoka dancing!!
いちご
ことり「SchoolIdol
クラスというのを定義しています。スクールアイドルを扱うための型だね」
凛「え~っと、class SchoolIdol
から見ていけばいいのかにゃ?」
ことり「うん。ざっと見ると、変数が3個、関数が2個、クラスが1個、あとinit
とかconstructor
っていうのが並んでるよね」
凛「変数と関数は見慣れた感じだね」
ことり「で、main
の方を見ると、var honoka = SchoolIdol("honoka", SchoolIdol.Profile("いちご", 78, 58, 82))
っていうコードがあります。ここが、SchoolIdol
のインスタンスを作ってるところ」
凛「インスタンス?」
ことり「SchoolIdol
クラスはスクールアイドルという概念。それに対してインスタンスはスクールアイドル個人個人。穂乃果ちゃんとか海未ちゃんとか、ツバサさんとか千歌ちゃんとか」
凛「ここで作ってるのは穂乃果ちゃんなんだね」
ことり「そうそう。ここで、名前とか好きな食べ物とかスリーサイズを渡してhonokaオブジェクトを生成してます」
凛「あっ、それに対してhonoka.sing()
とかでさっきの関数が呼べるんだ!」
ことり「正解。クラスの中に書いてあった関数や変数は、こうしてクラスのインスタンスに対して呼び出すことができます」
ことり「次はinit
とconstructor
かな。これは今まで出てこなかったけど、クラスの初期化を行うコンストラクタという仕組みです」
凛「初期化?」
ことり「穂乃果ちゃんオブジェクトを作った時点で、名前とかは設定されてた方がいいよね。それをやるための仕組みだよ」
ことり「もう一回、var honoka = SchoolIdol("honoka", SchoolIdol.Profile("いちご", 78, 58, 82))
を見ると、class SchoolIdol(name: String, profile: Profile)
となんとなく対応付いてるのわかるかな」
凛「そういえば・・・」
ことり「インスタンスを作るときに渡された値は、class
の宣言のところの引数並びと一致します。それを処理するためのブロックがinit
で、この仕組みをプライマリコンストラクタといいます」
ことり「今度は海未ちゃんを見てみようか。var umi = SchoolIdol("umi", "Otonokizaka High.", SchoolIdol.Profile("ほむまん", 76, 58, 80))
だから、引数が1つ多いよね」
凛「学校名が増えてるにゃ」
ことり「この場合、さっきのプライマリコンストラクタには当てはまらないから、今度はconstructor
で宣言されたセカンダリコンストラクタに処理が渡ります」
凛「なるほど~、こっちだと数が合うにゃ」
ことり「this(name, profile)
っていうのはプライマリコンストラクタの呼び出し。だから、セカンダリコンストラクタではプライマリになかった処理だけ書けばいいの」
ことり「最後に、class
の中にあるclass
、ネステッドクラス。・・・といってもこれは普通のクラスとほとんど同じで、SchoolIdol.Profile
みたいに書くとアクセスできます」
凛「SchoolIdol.Profile("いちご", 78, 58, 82)
みたいなのさっきから出てきてたよね」
ことり「あるクラスと関係性の深いクラスをネステッドクラスとして表現することがあります。それと、これの変種としてインナークラスっていうのもあってね」
凛「インナー・・・ネステッドとあんまり変わらない気がするにゃ」
ことり「例えば・・・」
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class SchoolIdol(name: String, profile: Profile) { var name: String var school: String var profile: Profile init { this.name = name this.school = "" this.profile = profile } constructor (name: String, school: String, profile: Profile) : this(name, profile) { this.school = school } class Nested { fun name() { println(name) // compile error } } inner class Inner { fun name() { println(name) } } } |
ことり「Nested
はネステッドクラス、Inner
はインナークラス。どっちも外側のname
変数を参照しようとしてるけど、Inner
からは参照できるけどNested
からは参照できません」
凛「スコープが違うんだね」
ことり「クラスについては勉強することがとてもたくさんあるから、まだまだ続くよ」
凛「ばっちこいにゃ!」