Kotlin-データクラス

4645 ワード

概要


開発の過程で、論理機能がなく、データを保存するために使用されるデータが作成されることがよくあります.Kolinでは,これらのクラスを一括してデータクラスと呼び,キーワードdataでタグ付けする.
data class User(val name: String, val age: Int)

コンパイラは、メインコンストラクタで宣言されたすべてのプロパティに基づいて、次のメンバー関数を自動的に推定します.
  • equals()/hashCode()関数ペア、
  • toString()関数、出力フォーマットは"User(name=John,age=42)",
  • componentN()関数群、これらの関数はクラスの属性に対応し、関数名の数字は1からNで、属性の宣言順序と一致し、
  • copy()関数
  • このデータクラスまたはベースクラスに上記のメンバー関数が書き換えられている場合、書き換えに準じて自動的に推定されません.

    データクラスの宣言条件

  • メインコンストラクタには少なくとも1つのパラメータが必要です.
  • メインコンストラクタのすべてのパラメータはvalまたはvarとしてマークする必要があります.
  • データクラスは抽象クラス、openクラス、閉鎖クラス、または内部(inner)クラスであってはならない.
  • データクラスは、他のクラスから継承できません(ただし、インタフェースを実装できます).

  • データクラスにコンストラクション関数があるかどうかは、プライマリコンストラクション関数でメンバー属性を初期化する必要があります.
    data class User(val name: String = "", val age: Int = 0)
    

    オブジェクトのコピー


    前述したように、JVMはデータクラスのcopy()関数を自動的に生成します.copy()はいったい何に使いますか.copy()はオブジェクトの浅いコピーですか、それとも深いコピーですか.これらの疑問を持って下を見る.
    data class Person(var name: String, var age: Int) {
    }
    
    data class MyInfo(val no: Int, var person: Person) {
    
    
        override fun hashCode(): Int {
            return super.hashCode()
        }
    }
    
    fun main(args: Array) {
    
        var per0: Person = Person("A", 20)
        var per1: Person = per0.copy(age = 15)
    
        println("------- Log0 -------")
    
        println("per0: $per0")
        println("per1: $per1")
    
        println("------- Log1 -------")
    
        per1.name = "B"
        println("per0: $per0")
        println("per1: $per1")
    
        println("------- Log2 -------")
    
        var info0: MyInfo = MyInfo(1, per0)
        var perAA = Person("AA", 30)
        var info1: MyInfo = info0.copy(no = 2)
        var info2: MyInfo = info0.copy(person = perAA)
    
        println("info0: $info0")
        println("info1: $info1")
    
        println("------- Log3 -------")
        info1.person.name = "C"
    
        println("info0: $info0")
        println("info1: $info1")
    
        println("------- Log4 -------")
    
        println("info0: $info0")
        println("info1: $info1")
        println("info2: $info2")
    
        println("------- Log5 -------")
        info2.person.name = "AC"
        println("info0: $info0")
        println("info1: $info1")
        println("info2: $info2")
        println("perAA: $perAA")
    }
    
    // Log 
    ------- Log0 -------
    per0: Person(name=A, age=20)
    per1: Person(name=A, age=15)
    ------- Log1 -------
    per0: Person(name=A, age=20)
    per1: Person(name=B, age=15)
    ------- Log2 -------
    info0: MyInfo(no=1, person=Person(name=A, age=20))
    info1: MyInfo(no=2, person=Person(name=A, age=20))
    ------- Log3 -------
    info0: MyInfo(no=1, person=Person(name=C, age=20))
    info1: MyInfo(no=2, person=Person(name=C, age=20))
    ------- Log4 -------
    info0: MyInfo(no=1, person=Person(name=C, age=20))
    info1: MyInfo(no=2, person=Person(name=C, age=20))
    info2: MyInfo(no=1, person=Person(name=AA, age=30))
    ------- Log5 -------
    info0: MyInfo(no=1, person=Person(name=C, age=20))
    info1: MyInfo(no=2, person=Person(name=C, age=20))
    info2: MyInfo(no=1, person=Person(name=AC, age=30))
    perAA: Person(name=AC, age=30)
    

    まず2つのデータクラスPersonとMyInfoを作成したが,MyInfoクラスにはPersonメンバー属性があり,PersonとMyInfoインスタンスをそれぞれ作成し,そのcopy()関数をそれぞれ用いて新しいオブジェクトを生成した.
  • ログ0とログ1から分かるように、copy()で得られたオブジェクトがその基本タイプの属性を変更した場合、元のオブジェクトには影響しません.
  • Log 2とLog 3の対比およびLog 4とLog 5の対比から、copy()関数を実行すると、参照タイプの場合、その参照オブジェクトはコピーされた新しいオブジェクトを指し、新しいオブジェクトが作成されたわけではありません.

  • すなわち、copy()関数は、オブジェクトをコピーし、一部のプロパティを変更しますが、他のプロパティは変更されません.copyは単純なレプリケーションではなく、新しいオブジェクトを作成します.基本タイプのプロパティでは値がコピーされ、値が割り当てられますが、参照タイプではアドレスを渡すか、浅いコピーを行うかで、新しいオブジェクトは作成されません.copy()って実际には浅いコピーと深いコピーの组み合わせだと思いますが、よくわかりませんね.
    "="番号付与については,浅いコピーが行われていることがよく知られているが,ログ1からは,基本データ型であっても,新しいオブジェクトの基本タイプ属性付与時には,元の値の属性を映像化することができる.
    var per0: Person = Person("A", 20)
    var per1: Person = per0
    
    ------- Log0 -------
    per0: Person(name=A, age=20)
    per1: Person(name=A, age=20)
    ------- Log1 -------
    per0: Person(name=B, age=20)
    per1: Person(name=B, age=20)
    

    「=」番号付与とcopy()は、実行メカニズムに違いがあります.copyを使用する場合は、リファレンスタイプの浅いコピーに注意し、少し注意すると大きなエラーが発生します.の

    データの解体


    前述したように、JVMはデータクラスからクラスの属性に対応するいくつかの列のコンポーネント関数(componentN()関数群)を生成し、関数名の数字1からNは、属性の宣言順序と一致し、これらのコンポーネント関数があれば、解構宣言でデータを使用することができる.
    val jane = Person("Jane", 35)
    val (n, a) = jane
    println("$n, $a years of age") //   "Jane, 35 years of age"