オブジェクトとは
    多くのプログラミング言語では、「オブジェクト」といえは、
    インスタンス化されたクラスの実際のデータを指します。
    つまり、インスタンスとオブジェクトは同じ意味で使われています。
    しかし、Kotlinでは「オブジェクト」というと別のことを意味します。
    Kotlinでは、
    「あるクラスをちょっとだけ変更したものを一時的に利用したい場合、
     そのクラスを継承したものをその場で作成する」とか
    「一時的にちょっとしたクラスを作って利用したいときにその場でクラスをつくる」
    という場合に「オブジェクト」を作成すると言います。
    そして、その作成した一時的なクラスを「オブジェクト」と呼びます。
    Javaでは「匿名クラス」と呼ばれていた機能に相当します。
オブジェクトの使い方
    それではまず「あるクラスをちょっとだけ変更したものを一時的に利用したい場合、
    そのクラスを継承したものをその場で作成する」というサンプルを確認します。
    この場合は、既存クラスをその場で継承してオーバーライドするということをその場で実施します。
fun main(args: Array) {
    val student1 = Student("suzuki", 80.0)
    student1.describe()
    // その場でStudentの関数をオーバーライドして、少しだけ処理を変更した「オブジェクト」を作成する
    // 基底クラスにプライマリコンストラクタがある場合、その場で値を渡さなければなりません
    val student2 = object : Student("tanaka", 65.0) {
        override fun describe() = print("Name: ${name}\nScore: ${score}\n")
    }
    student2.describe()
}
open class Student(val name: String, var score: Double) {
    open fun describe() = println("Name is ${name} and score is ${score}.")
}  Name is suzuki and score is 80.0.
Name: tanaka
Score: 65.0 
    次に、 「一時的にちょっとしたクラスを作って利用したいときにその場でクラスをつくる」
    場合のサンプルを見てみましょう。
    こちらは、クラスをその場で実装するような感じで利用します。
fun main(args: Array) {
    // ちょっとしたデータや関数の集まりをその場で用紙できる。
    val p = object {
        val name = "suzuki"
        var score = 55.5
        fun describe() = println("Name: ${name} Score: ${score}")
    }
    p.score = 80.0
    p.describe()
}  Name: suzuki Score: 80.0 クラスを構成するオブジェクト
    オブジェクトはあくまで「その場限り」つまり「ローカル」なモノです。
    関数やプロパティなどのクラスメンバーは返り値としてオブジェクトを返すことができますが、
    そのオブジェクトを利用できるのは、そのクラスの内部だけです。
    そのためpublicなメンバーの返り値としてオブジェクトを返しても、
    その型は自動的に「Any」になるため、オブジェクトのメンバーにアクセスすることができません。
fun main(args: Array) {
    val student = Student("suzuki", 80.0)
    student.testObject()
}
class Student(val name:String, var score: Double) {
    private val description
        get() = object {
            val typeA = "Name: ${name} Score: ${score}"
            val typeB = "Name is ${name} nad score si ${score}"
        }
    fun foo() = object {
        val x = 100
        val y = 200
    }
    fun testObject() {
        // privateメンバーであれば、オブジェクトを期待通りに利用できる
        println(description.typeA)
        println(description.typeB)
        // foo()はpublicなので、オブジェクトを返しても、自動的に「Any」となる。
        // そのため、オブジェクtのメンバーには結局アスセスすることができない
        // 次のコードはビルドエラーになる
        // println(foo().x)
    }
}  Name: suzuki Score: 80.0
Name is suzuki nad score si 80.0 オブジェクト宣言
    ここまでのオブジェクトは名前のついていない、つまり匿名オブジェクトでした。
    しかし、実は「名前付き」のオブジェクトを作成することができます。
    これは、いわゆる「シングルトン」として機能します。
fun main(args: Array) {
    // Cache自体を一種の変数のように扱えるた、
    // Cacheは一つしかない
    Cache.add("suzuki")
    Cache.add("tanaka")
    println(Cache.studentList)
}
// オブジェクト宣言(シングルトン)
object Cache {
    val studentList = mutableListOf()
    fun add(name: String) {
        if (!name.isEmpty()) {
            studentList.add(name)
        }
    }
}   [suzuki, tanaka] コンパニオンオブジェクト
    クラスメンバーとしてのオブジェクト宣言の場合、「companion」をつけることで、
    そのメンバーの呼出を簡単にすることができるようになります。
fun main(args: Array) {
    School.add("suzuki")
    School.add("tanaka")
    println(School.studentList)
}
// オブジェクト宣言(シングルトン)
class School {
    companion object Cache {
        val studentList = mutableListOf()
        fun add(name: String) {
            if (!name.isEmpty()) {
                studentList.add(name)
            }
        }
    }
}   [suzuki, tanaka]