FLORINA MUNTENESCU: A puppy has a name, a breed,
and a whole lot of cuteness.
To model a class that just holds data,
you should use a data class.
The compiler simplifies your work by auto-generating
toString, equals, and hashCode, and providing the structuring
and copy-functionality out of the box,
letting you focus on the data you need to represent--
the puppy.
In this video, I'll tell you more about other advantages
of data classes, their restrictions,
and we'll take a look under the hood
at how they're implemented.
If you learned something new, like the video,
and subscribe to the channel, but only if you think
we've earned it.
[MUSIC PLAYING]
FLORINA MUNTENESCU: To declare a data class,
use the data modifier, and specify
the properties of the class as val or var parameters
in the constructor.
As with any other class, you can provide default arguments.
You can directly access and modify properties, and define
functions inside your class.
But you can get several advantages
over regular classes.
So first, toString, equals, and hashCode
are implemented for you by the Kotlin compiler,
removing the need to remember to update them every time you
add or update your properties.
Second advantage, the structure.
Third advantage, ease of copying by calling the copy method.
Data classes come with a series of restrictions.
So data classes were created as a data holder.
And because this is enforced, you
have to pass at least one parameter
to the primary constructor.
And the parameters need to be val or var properties.
Trying to add a parameter without val or var
leads to a compile error.
As a best practice, consider using vals instead of vars
to promote immutability.
Otherwise, subtle issues can appear--
for example, when using data classes
as keys for HashMap objects, as the container
can get in an invalid state when the var value changes.
Trying to add a vararg parameter in the primary constructor
leads to a compile error as well.
So vararg is not allowed, due to how
equals works on the JVM for arrays and collections.
Andrey Breslav explains, "Collections
are compared structurally, while arrays are not.
Equals, for them, simply resorts to referential equality.
This equals other."
Data classes can inherit from interfaces, abstract classes,
and classes, but cannot inherit from other data classes.
Data classes can't be marked as so.
For example, adding "open" will result in an error.
Modifier "open" is incompatible with data.
Let's check what exactly does Kotlin
generate, to be able to understand how some
of these features are possible.
So to do this, we'll look at the Java decompile code.
So tools, Kotlin, show Kotlin, and bytecode,
and then press the Decompile button.
Like with a regular class, puppy is a public final class,
containing the properties we defined,
and the getters and setters for that.
The constructor we define is generated.
Then, because we used the default argument
in the constructor, then we get the second synthetic
constructor as well.
To find out more about default arguments
and the generated code, check out our Kotlin vocabulary
video.
Then Kotlin generates the toString, hashCode,
and equals methods.
When you modify the data class updating properties,
the right method implementations are generated for you
automatically.
Like this, you know that hashCode and equals will never
be out of sync.
While toString and hashCode are quite straightforward,
and look similar to the way you'd implement it,
equals uses Intrinsics.areEqual that
performs a structure equality.
By using a method call, rather than direct implementation,
the Kotlin language developers get more flexibility,
as they can change the implementation of our equals
in future language versions, if needed.
To enable this structuring, data classes
generate components and methods that just return as fields.
The component number follows the order
of the constructor parameters.
Find out more about the structuring from our Kotlin
vocabulary video.
Data classes generate a copy method
that can be used to create a new instance of the object,
keeping zero or more of the original values.
You can think of copy as a method that
gets all fields of the data class as parameters,
with the values of fields as default values.
Knowing this, you won't be surprised
that Kotlin generates two copy methods--
copy and copy default. The latter
is a synthetic method that ensures
that when a value isn't passed in for a parameter,
then the right value is used from the base class.
Data classes are in front of the most used Kotlin features,
and for good reason.
They decrease the boilerplate code
you need to write, enable features
like destructuring and copying an object,
and let you focus on what matters--
your app.
Thanks for watching.
And go write better Android apps with Kotlin.
[MUSIC PLAYING]