Kotlin 1.5 announced a blockbuster feature value class, which is a very practical feature to improve code readability and performance, because the compiler will further optimize it and reduce the creation of objects.
With the continuous improvement of Kotlin, a series of features have emerged inner class , data class , sealed class , sealed interface , inline class , value class wait
Today's article mainly analyzes inline class and value class.
Through this article, you will learn the following:
- What is an inline function?
- When do you use inline functions?
- What is? inline class ?
- What is? value class ?
- value class Cannot be inherited
- value class Interface can be implemented
- When the passed object is empty, the inline effect is lost
- value class Prohibited use === have access to ==
- inline class and value class What's the difference?
- How does Java call functions that accept inline classes?
Inline function
Passed in Kotlin inline-functions Inline function is used to realize function inlining. The function of inlining is to improve operation efficiency and the call is called inline Modifier function will put the code in the method body where it is called. Its main purpose is to improve performance and reduce the creation of objects. The inline function code is shown below.
fun testInline() { printByteCode() } inline fun printByteCode() { println("printByteCode") } // After compilation public static final void testInline() { String var1 = "printByteCode"; System.out.println(var1); }
inline The modified function applies to the following cases
- inline Modifiers are used to take a function as an argument to another function, such as a higher-order function filter , map , joinToString Or some independent functions repeat
- inline Operators fit and reified Operators are used together
- If the function body is short, use inline Operators improve efficiency
If used inline The modifier marks ordinary functions, and Android Studio will give a big warning, as shown in the figure below, to prevent inline Performance loss caused by operator abuse.
But if the function body is very short, you want to pass inline Operators to improve efficiency, but also want to eliminate the warning, you can go to check Kotlin skills and analysis that few people know (3) "Use of Kotlin annotations in projects" in the article.
Inline class
Inline classes are an overlooked and very useful feature. Sometimes necessary business logic needs to encapsulate basic data types, strings and other parameters in a Model, and then encapsulate some methods in the Model to check and verify this parameter.
After the parameters are encapsulated, a wrapper object needs to be created. The creation of objects is allocated in the heap. In the case of a large amount of data, the loss of performance is also very large, such as memory occupation, runtime efficiency, frequent creation of objects, resulting in the Caton problem caused by GC recycling a large number of objects, and so on.
The runtime JVM will optimize the basic data type, String, etc., but if these parameters are encapsulated in a class, the wrapper class will not do any processing and will still create objects in the heap.
Therefore, in order to reduce performance loss and avoid object creation, Kotlin introduced an inline class inline-classes . An inline class can only pass in one parameter in the constructor. The parameter needs to be declared with val. after compilation, it will be replaced with the passed in value. The code is as follows.
inline class User(val name: String) fun testInline() { println(User("DHL")) } // After compilation public static final void testInline() { System.out.println("DHL"); }
As you can see, the compiled Java code does not create additional objects. The objects created in Kotlin are replaced with the values passed in.
How does Java call functions that accept inline classes
Declare a function in Kotlin and inline class Pass it as a parameter. After compiling into Java code, the function name will be confused. The code is as follows.
inline class User(val name: String) fun login(user: User) { } // Compiled code public static final void login_FY_U7ig/* $FF was: login-FY_U7ig*/(@NotNull String user) { }
The compiled function name will be scrambled, for example login-FY_U7ig. However, there is a problem. Java cannot call functions that accept inline classes. The code is as follows.
inline class User(val name: String) fun login(user: User) { } fun login(passwd: String) { } // Kotlin compilation is normal login(User("DHL")) login("ByteCode") // Java compilation failed MainKt.login("DHL");
The call can be compiled in Kotlin, because the inline causes cause the Java call to fail, as shown in the following figure.
In order to be called normally in Java, annotations are added @ JvmName Change the function name to solve this problem. The code is as follows.
inline class User(val name: String) @JvmName("loginWithName") fun login(user: User) { } fun login(passwd: String) { } // Kotlin compilation is normal login(User("DHL")) login("ByteCode") // Java compilation is normal MainKt.loginWithName("DHL");
So whether it's Inline classes still Value classes If not added @ JvmName Annotation, there will be this problem. The purpose of confusing the generated function names is to prevent method overload conflicts or accidental Java calls.
Inline classes It was introduced in Kotlin 1.3. It entered the stable version in Kotlin 1.5 and was abandoned inline Modifier, introduced Value classes.
What is Value classes
Inline classes yes Value classes A subset of, Value classes than Inline classes Will get more optimization at this stage Value classes and Inline classes Similarly, only one parameter can be passed in the constructor, and the parameter needs to be Val declares that multiple parameters can be added to the constructor in the future, but each parameter needs to be used val The official statement is shown in the figure below.
If you support adding multiple parameters in the future, it will be used more and more widely.
After upgrading to Kotlin 1.5, Inline classes Will be deprecated, as shown in the figure below, and the compiler will give a warning.
According to the prompt, the only thing that needs to be changed at present is the syntax inline Replace with value, and then add @ JvmInline Just annotate.
@JvmInline value class User(val name: String)
Compiled effects and Inline classes Is the same, so the following cases will use Value classes.
Value classes cannot be inherited
because value class It will be added after compilation fianl Modifier, so it cannot be inherited, nor can it inherit other classes, as shown in the following figure.
Value classes can implement interfaces
although value class You cannot inherit other classes, but you can implement the interface. The code is as follows.
interface LoginInterface @JvmInline value class User(val name: String) : LoginInterface fun testInline() { println(User("DHL")) } // Compiled code public static final void testInline() { User var0 = User.box-impl(User.constructor-impl("DHL")); System.out.println(var0); } public static final User box_impl/* $FF was: box-impl*/(String v) { return new User(v); }
As the code shows, when value class When implementing the interface, the inline effect is lost and will still be created in the heap User Object has no inline effect except when implementing the interface. When the object is empty, the inline effect will also be lost.
When the passed object is empty, the inline effect will be lost
When the parameter of the constructor is the basic data type, and the passed parameter value class When the object of is empty, the inline effect will be lost. The code is as follows.
@JvmInline value class User(val age: Int) fun login(user: User?): Int = user?.age ?: 0 fun testInline() { println(login(User(10))) } // Compiled code public static final int login_js0Jwf8/* $FF was: login-js0Jwf8*/(@Nullable User user) { return user != null ? user.unbox-impl() : 0; } public static final void testInline() { int var0 = login-js0Jwf8(User.box-impl(10)); System.out.println(var0); } public static final User box_impl/* $FF was: box-impl*/(int v) { return new User(v); }
As you can see, it will still be created in the heap User Object, the inline effect is lost because Int Cannot convert directly to null.
When the constructor parameter is String, and passed parameters value class When the object of is empty, the inline effect will not be affected. The code is as follows.
@JvmInline value class User(val name: String) fun login(user: User?): String = user?.name ?: "" fun testInline() { println(login(User("DHL"))) } // Compiled code public static final String login_js0Jwf8/* $FF was: login-js0Jwf8*/(@Nullable String user) { // ...... return var10000; } public static final void testInline() { String var0 = login-js0Jwf8("DHL"); System.out.println(var0); }
The compiled Java code does not create an object and passes it to the method login Parameters of User Is replaced by the value passed in String.
Value class prohibited = = = available==
Operators in Kotlin == and === For more information, you can go to Uncover = = and in Kotlin=== , here is a brief introduction.
Kotlin provides two ways to compare objects.
-
Are the structures of the comparison objects equal( == perhaps equals )
Operators in Kotlin == Equivalent to equals It is used to compare whether the structures of objects are equal. In many cases, it is used ==, Because for floating-point types Float and Double, their implementation methods equals Does not comply with IEEE 754 floating point standard.
-
Compare whether references to objects are equal( === )
Operators in Kotlin === It is used to compare whether the reference of an object points to the same object. If it is a basic data type at runtime === Equivalent to ==.
among value class It is special. Operators are prohibited ===, As shown in the figure below, the compiler will give a warning.
Because operators === It is used to compare whether the references of objects are equal. Because of inlining, they will eventually be replaced with the passed in value.
But operator == Is unaffected, operator == It is used to compare whether the structures of objects are equal. The code is as follows.
fun testInline() { val u1 = User("DHL") val u2 = User("DHL") println(u1 == u2) } // Compiled code public static final void testInline() { String u1 = "DHL"; String u2 = "DHL"; boolean var2 = User.equals-impl0(u1, u2); System.out.println(var2); }
If it's helpful, a compliment is my greatest encouragement
More code, more articles