Table of Contents
If you just heard about JvmInline (Inline) Class, you can read articles below:
Let’s dig dive what JvmInline (Inline) can and can not with some code preview.
Can be only final and can not be open or abstract
// Correct
@JvmInline
value class ExampleInline(private val value: String)// Incorrect
@JvmInline
open value class ExampleInline(private val value: String)
// Incorrect
@JvmInline
abstract value class ExampleInline(private val value: String)
Can be extend to Interface but can not extend to another Class
open class ExampleClass
interface ExampleInterface// Correct
@JvmInline
value class ExampleInline(private val value: String) : ExampleInterface
// Correct
@JvmInline
value class ExampleInline(private val value: ExampleInterface) : ExampleInterface by value
// Incorrect
@JvmInline
value class ExampleInline(private val value: String) : ExampleClass
Can only have one immutable property (whether public or private) and can not have mutable property or multiple property
// Correct
@JvmInline
value class ExampleInline(
// One private immutable property
private val value: String
)
// Correct
@JvmInline
value class ExampleInline(
// One public immutable property
val value: String
)// Incorrect
@JvmInline
value class ExampleInline(
// One private mutable property
private var value: String
)
// Incorrect
@JvmInline
value class ExampleInline(
// Multiple private mutable property
private var value1: String,
private val value2: String
)
Can declare properties but can not have properties with backing fields.
@JvmInline
value class ExampleInline(private val value: String) // Correct
val length: Int
get() = value.length
// Incorrect
// Value class can't have properties with backing fields
private val id1: Int = 0
// Incorrect
// Value class can't have properties with backing fields
private var id2: Int = 0
// Incorrect
// Value class can't have properties with backing fields
private lateinit var id3: Int
Can declare functions and override toString function, but can not override equals and hashCode function
@JvmInline
value class ExampleInline(private val value: String) // Correct
init
println("Init ExampleInline")
// Correct
fun greeting()
println("Hello $value")
// Correct
override fun toString(): String
return value
// Incorrect
// Member with the name 'equals' is reserved for future releases
override fun equals(other: Any?): Boolean
return super.equals(other)
// Incorrect
// Member with the name 'hashCode' is reserved for future releases
override fun hashCode(): Int
return super.hashCode()
Can compare by equals function, but can not by referential equality
fun main()
val exampleInline1 = ExampleInline("ABC")
val exampleInline2 = ExampleInline("ABC")// Correct
assertEquals(exampleInline1, exampleInline1)
// Correct
assertEquals(exampleInline1, exampleInline2)
// Incorrect
// expected:<ExampleInline(value=ABC)> but was:<ABC>
assertEquals(exampleInline1, "ABC")
// Incorrect
// Identity equality for arguments of types ExampleInline and ExampleInline is forbidden
assertEquals(exampleInline1 === exampleInline1)
// Incorrect
// Identity equality for arguments of types ExampleInline and ExampleInline is forbidden
assertEquals(exampleInline1 === exampleInline2)
val list = listOf(
exampleInline1, exampleInline2
)
val map = mapOf(
"1" to exampleInline1,
"2" to exampleInline2
)
// Correct
assertTrue(list.contains(exampleInline1))
// Correct
assertTrue(list.contains(ExampleInline("ABC")))
// Correct
assertTrue(list.contains(ExampleInline("ABC")))
// Correct
assertTrue(map.containsValue(exampleInline1))
// Correct
assertTrue(map.containsValue(ExampleInline("ABC")))
JvmInline (Inline) Class don’t have an identity and can only hold values. It because they are subset of value-based classes. And it will impact to the memory allocation as well. In example:
class ExampleActivity : AppCompatActivity() val exampleInline: ExampleInline = ExampleInline("")
val exampleNotInline: ExampleNotInline = ExampleNotInline("")
@JvmInline
value class ExampleInline(private val value: String)
class ExampleNotInline(private val value: String)
And when do heap dump memory:
ExampleInline
can not be seen on memory allocation.
Can write code to initiate JvmInline (Inline) Class but can not be compiled
public void main()
// We can write this code, but got error when build
ExampleInline exampleInline = new ExampleInline("ABC");
/*
Error when build
ExampleTest.java:9: error: cannot find symbol
ExampleInline exampleInline = new ExampleInline("ABC");
^
symbol: constructor ExampleInline(String)
location: class ExampleInline
*/
public void main()
// We can write this code, but got error when build
Constructor<ExampleInline> constructor = ExampleInline.class.getConstructor(String.class);
ExampleInline exampleInline = constructor.newInstance("ABC");
/*
ExampleInline.<init>(java.lang.String)
java.lang.NoSuchMethodException
*/
Always be seen as underlying value on Java code
fun String.toInline(): ExampleInline = ExampleInline(this)@JvmName("greeting1") // to manually disable mangling and given name on the JVM
fun String.greeting()
println("Hello $this")
@JvmName("greeting2") // to manually disable mangling and given name on the JVM
fun greeting(value: String)
println("Hello $value")
@JvmName("greeting3") // to manually disable mangling and given name on the JVM
fun greeting(exampleInline: ExampleInline)
println("Hello $exampleInline")
Not if we implement an interface on inline class, it could be seen as the interface
interface ExampleInterface@JvmInline
value class ExampleInline(private val value: String) : ExampleInterface
fun String.toInterface(): ExampleInterface = ExampleInline(this)
fun greeting(exampleInline: ExampleInterface)
println("Hello $exampleInline")