Kotlinのデータクラス

このチュートリアルでは、Kotlinのデータクラスを見ていきます。まだKotlinクラスの投稿を読んでいない場合は、進む前にそちらをお勧めします。

Kotlinデータクラス

JavaでPOJOデータクラスのために何千行ものコードを書くのにうんざりしませんか?どのJavaプログラマーも、単にいくつかのデータを保存するだけのクラスのために書かなければならないコード行数に注目したことがあるはずです。では、Book.javaのPOJOクラスはどのように見えるでしょうか:

public class Book {

    private String name;
    private String authorName;
    private long lastModifiedTimeStamp;
    private float rating;
    private int downloads;


    public Book(String name, String authorName, long lastModified, float rating, int downloads) {
        this.name = name;
        this.authorName = authorName;
        this.lastModifiedTimeStamp = lastModified;
        this.rating = rating;
        this.downloads = downloads;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

    public long getLastModifiedTimeStamp() {
        return lastModifiedTimeStamp;
    }

    public void setLastModifiedTimeStamp(long lastModifiedTimeStamp) {
        this.lastModifiedTimeStamp = lastModifiedTimeStamp;
    }

    public float getRating() {
        return rating;
    }

    public void setRating(float rating) {
        this.rating = rating;
    }

    public int getDownloads() {
        return downloads;
    }

    public void setDownloads(int downloads) {
        this.downloads = downloads;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Book that = (Book) o;

        if (downloads != that.downloads)
            return false;
        if (name != null ? !name.equals(that.name) :
                that.name != null) {
            return false;
        }
        return authorName != null ?
                authorName.equals(that.authorName) :
                that.authorName == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (authorName != null ?
                authorName.hashCode() : 0);
        result = 31 * result + downloads;
        return result;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + authorName + '\'' +
                ", lastModifiedTimestamp='" + lastModifiedTimeStamp + '\'' +
                ", rating='" + rating + '\'' +
                ", downloads=" + downloads +
                '}';
    }
}

わー!わずか5つのフィールドを保存するために96行のコードが必要です。ここでは、ゲッターセッター、toString()equals()、およびhashCode()メソッドを持っています。クリーンアーキテクチャやコードの分離の慣行により、プロジェクトごとにデータを保存する必要があるため、POJOクラスを作成する必要があります。これにより、雛形コードが増加する可能性があります。ここでKotlinが救いの手を差し伸べます。Dataクラスは、Kotlinが雛形コードを削減するための答えです。上記のPOJOクラスは、Kotlinで次のように書くことができます:

data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

それだけです。Kotlinは、96行のJavaコードを1行のコードに変換します。これが、Kotlinがプロジェクト内の雛形コードを削減する方法です!

Kotlinのデータクラスの作成

次に、Kotlinのデータクラスを作成するための要件を示します。

  • クラス名にはキーワードdataを追加する必要があります。
  • プライマリコンストラクタには少なくとも1つのパラメータが必要です。
  • プライマリコンストラクタの各パラメータには、valまたはvarが割り当てられている必要があります。 これは通常のクラスでは必須ではありませんが、valまたはvarの指定が必須ではありません。
  • データクラスには、abstractopensealed、またはinnerを追加できません。

Kotlinデータクラスの組み込みメソッド

Kotlinデータクラスは、自動的に以下の関数を作成します。

  • equals()およびhashCode()
  • toString()は、"Book(name=JournalDev, authorName=Anupam)"のような形式です。
  • 指定された順序で各パラメータのためのcomponentN()関数が作成されます。 これは分解宣言として知られています。
  • copy()

Kotlinのデータクラスの特徴

以下は、データクラスが提供するいくつかの機能です。

  • パラメータなしのコンストラクタを作成するには、プライマリコンストラクタ内の各パラメータにデフォルト値を指定します。

  • データクラスはサブクラス化を許可します(キーワードopenを記述する必要はありません)。

  • equals()hashCode()、およびtoString()関数の明示的な実装を提供できます。

  • copy()およびcomponentN()関数の明示的な実装は許可されていません。

  • 以下に示すように、コンストラクタ内で可視性修飾子を指定することで、ゲッターとセッターの可視性を制御できます。

    data class Book(var name: String,private var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)
    
  • 以下に示すように、コンストラクタで可視性修飾子を指定することで、getterおよびsetterの可視性を制御できます。

Data Classのデフォルトと名前付き引数

次が私たちのデータクラスです:

data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

パラメーターにはデフォルト値が設定されていません。そのため、以下に示すようにインスタンス化の際にそれぞれの引数に対して引数を設定する必要があります。

fun main(args: Array<String>) {
val book = Book("Android Tutorials","Anupam", 1234567, 4.5f, 1000)
}

いくつかのデフォルト引数を設定して、インスタンス化がどのように変わるかを見てみましょう。


data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)
fun main(args: Array<String>) {
var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    book = Book("Kotlin")
    book = Book("Swift",downloads = 500)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    book = Book("Python","Shubham",rating = 5f)

}

各引数を設定する代わりに、名前付き引数を使用して、非デフォルトの引数と希望する引数だけを設定できます。名前付き引数を使用すると、パラメーター名を明示的に指定して=に続けて5番目の引数を2番目に設定できます。こちらの方がずっと簡単ですね!

Kotlin Data ClassのtoString()メソッド

toString()メソッドは暗黙的に作成され、以下に示すようにインスタンスの引数名とラベルを表示します。

data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)


fun main(args: Array) {

    var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)
    book = Book("Kotlin")
    println(book)
    book = Book("Swift",downloads = 500)
    println(book)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    println(book.toString())
    book = Book("Python","Shubham",rating = 5f)
    println(book.toString())


}

//以下はコンソールに印刷されます。
//Book(name=Android tutorials, authorName=Anupam, lastModified=1234567, rating=4.5, downloads=1000)
//Book(name=Kotlin, authorName=Anupam, lastModified=1234567, rating=5.0, downloads=1000)
//Book(name=Swift, authorName=Anupam, lastModified=1234567, rating=5.0, downloads=500)
//Book(name=Java, authorName=Pankaj, lastModified=1234567, rating=5.0, downloads=1000)
//Book(name=Python, authorName=Shubham, lastModified=1234567, rating=5.0, downloads=1000)

注意: print 関数は暗黙的に toString() を追加します。

Kotlin Data Class copy() メソッド

Copy 関数は、データクラスのインスタンスのコピーを作成し、いくつかのプロパティを変更します。データクラスのコンストラクタで val パラメータを使用して、インスタンスのイミュータブル プロパティを使用することをお勧めします。イミュータブル オブジェクトは、マルチスレッド アプリケーションで作業する際に便利です。したがって、いくつかのプロパティを変更してイミュータブル オブジェクトのコピーを作成するには、copy() 関数が便利です。

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)

    val newBook = book.copy(name = "Kotlin")
    println(newBook)
}
//以下はコンソールに印刷されます。
//Book(name=Android tutorials, authorName=Anupam, lastModified=1234567, rating=4.5, downloads=1000)
//Book(name=Kotlin, authorName=Anupam, lastModified=1234567, rating=4.5, downloads=1000)

Kotlin Data Class equals() と hashCode()

hashCode()メソッドはオブジェクトのハッシュコードを返します。2つのオブジェクトが等しい場合、hashCode()は同じ整数結果を生成します。したがって、equals()hashCode()が等しい場合にtrueを返し、それ以外の場合はfalseを返します。

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println("Hashcode is ${book.hashCode()}")

    val newBook = book.copy(name = "Kotlin")
    println("Hashcode is ${newBook.hashCode()}")

    val copyBook = book.copy()
    println("Hashcode is ${copyBook.hashCode()}")


    if(copyBook.equals(book))
        println("copyBook and book are equal")

    if(!book.equals(newBook))
        println("newBook and book are NOT equal")

}

//以下がコンソールに出力されます。
//ハッシュコードは649213087です。
//ハッシュコードは1237165820です。
//ハッシュコードは649213087です。
//copyBook と book は等しいです。
//newBook と book は等しくありません。

最初と三番目のオブジェクトのハッシュコードが等しいため、それらは等しいです。Note: equals()メソッドはKotlinにおける==に相当します。

Destructuring Declarations

componentN()関数を使用すると、コンストラクタで指定された引数のそれぞれにアクセスできます。Nはコンストラクタでのパラメータ数です。

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    println(book.component1()) //Android tutorials
    println(book.component2()) //Anupam
    println(book.component3()) //1234567
    println(book.component4()) //4.5
    println(book.component5()) //1000
    
}

デストラクチャ宣言を使用すると、以下に示すように、クラスオブジェクトから引数にアクセスできます。

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book
}

注意: 引数のいずれかにprivateなどの可視性修飾子が設定されている場合、上記の関数からアクセスできません。

data class Book(val name: String,private val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book //This won't compile since authorName is private
}

Kotlin Data Classesに関する簡単な概要は以上です。参考文献: Kotlin Docs

Source:
https://www.digitalocean.com/community/tutorials/kotlin-data-class