programowanieProgramista Backend

Wyjaśnij różnice między klasami danych (data classes), zwykłymi klasami a klasami z dziedziczeniem w Kotlin. W jakich przypadkach należy używać data class i jakie ograniczenia nakłada kompilator?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W Kotlin data class są przeznaczone do przechowywania danych. Kompilator automatycznie generuje dla nich metody equals(), hashCode(), toString(), a także funkcje copy() i componentN(), co zdecydowanie ułatwia pracę z takimi obiektami:

data class User(val name: String, val age: Int) val u1 = User("Ivan", 30) val u2 = u1.copy(age = 31)

Zwykłe klasy nie mają takich autogenerowanych metod; wszystko pisze się ręcznie. Data class lepiej używać do DTO, modeli i struktur danych.

Ograniczenia data class:

  • Konstruktor główny musi zawierać co najmniej jeden parametr.
  • Wszystkie parametry konstruktora muszą być oznaczone jako val lub var.
  • Data class nie może być abstract, open, sealed ani inner.
  • Nie zaleca się używania data class dla klas z logiką biznesową lub hierarchią dziedziczenia.

Pytanie z podchwytliwością

"Czy można zadeklarować data class dziedziczący od innego data class? Dlaczego (lub dlaczego nie)?"

Nie, nie można bezpośrednio dziedziczyć jednego data class od drugiego. Data class może dziedziczyć tylko od interfejsu lub zwykłej klasy (nie data class). Zostało to zrobione, aby zapobiec zamieszaniu z autogenerowanymi metodami (na przykład kopiowanie dziedziczonych właściwości nie jest oczywiste).

data class Base(val id: Int) data class Child(val name: String) : Base(1) // Błąd kompilacji: nie dozwolone

Przykłady rzeczywistych błędów z powodu nieznajomości niuansów tematu


Historia

W projekcie bankowym używano data class z logiką biznesową i dziedziczeniem. Po dodaniu nowego pola stało się niemożliwe poprawne kopiowanie obiektów, część logiki biznesowej została utracona (metody nie zostały odziedziczone), co doprowadziło do błędów w obliczeniach prowizji.


Historia

W platformie e-commerce data class był używany do przechowywania stanu koszyka użytkownika. Po zaktualizowaniu stanu przez copy(), zapomniano, że wewnętrzne listy nie są kopiowane głęboko. Z tego powodu występowało "przeciekanie" danych między sesjami użytkowników.


Historia

W projekcie z integracją zewnętrznego API serializacja data class do JSON prowadziła do pojawienia się pól o prywatnym zasięgu, co naruszało umowę API i prowadziło do błędów po stronie klienta.