Note: the coding tool is IntelliJ
catalogue
Generic implementation of custom map transformation
Joint generic function implementation of generic classes
Generic function implementation
Receive Java data with nullable types
Interface
The interface is open by default, and the interface members are open by default.
Example
interface InterfaceTest { fun test() } class InterfaceTestImpl : InterfaceTest{ override fun test() { println("This is implemented from InterfaceTest Method of") } } fun main() { InterfaceTestImpl().test() }
Output:
This is implemented from InterfaceTest Method of
Define variables
The implementation class can override the variables of the interface through constructor parameters or within the class.
There can be function default implementation inside the interface.
Example
interface InterfaceVariable { var name : String val des: String fun show(){ println("name = $name, des = $des") } } class InterfaceVariableImpl(override var name: String, override val des: String) : InterfaceVariable class InterfaceVariableImpl2(name: String, des: String): InterfaceVariable{ override var name: String = name override val des: String = des } fun main() { InterfaceVariableImpl("Happy", "Word").show() InterfaceVariableImpl2("Terminal", "When").show() }
Output:
name = Happy, des = Word name = Terminal, des = When
Variable defaults
Variables defined by the interface cannot be directly assigned with =, but variables modified by val can be assigned with get attribute.
Interface variables with default values can be overridden or not.
interface InterfaceVariable2 { val randNum: String get() = (1..100).shuffled().first().toString() val des : String get() = "Don't ask me where I come from" fun show(){ println("randNum = $randNum, des = $des") } } class InterfaceVariable2Impl: InterfaceVariable2 // If the variables in the interface have default values, they can not be overloaded class InterfaceVariable2Impl2(randNum: String, des: String): InterfaceVariable2{ override val randNum: String = randNum override val des: String = des } fun main() { InterfaceVariable2Impl().show() InterfaceVariable2Impl2("hahaha", "song").show() }
Output:
randNum = 89, des = Don't ask me where I come from randNum = hahaha, des = song
abstract class
Abstract classes are open by default, and abstract functions and attributes of abstract classes are open by default.
Abstract classes can have non Abstract member variables and non abstract functions.
If you want to override non Abstract member variables and non abstract functions, you need to add the open keyword.
Example
abstract class Abstract(age: Int) { abstract var name: String open var age: Int = age open fun show() { println("age = $age") } abstract fun show2() } class SubAbstract(override var name: String, override var age: Int) : Abstract(age) { override fun show2() { println("name = $name, age = $age") } override fun show() { println("override show") } } fun main() { val subAbstract = SubAbstract("Sjh", 30) subAbstract.show() subAbstract.show2() }
Output:
override show name = Sjh, age = 30
Implementation interface
Abstract classes can implement interfaces, either overriding interface members or not.
interface Animal{ fun show() } abstract class Cat: Animal abstract class Dog: Animal{ override fun show() { println("Dog Rewritten show") } } class Poodle: Dog() fun main() { Poodle().show() }
Output:
Dog Rewritten show
generic paradigm
Generic class
class GenericClass<T>(val t: T){ fun printAny() = println(t) } fun main() { GenericClass(123).printAny() GenericClass("hello").printAny() GenericClass(123.3987f).printAny() GenericClass('C').printAny() GenericClass(3214.908).printAny() }
Output:
123 hello 123.3987 C 3214.908
Generic Functions
fun <TYPE> getSelf(t: TYPE) = t.takeIf { t != null } ?: "t is null" fun main() { println(getSelf(null)) println(getSelf("Today is Sunday")) println(getSelf(234)) }
Output:
t is null Today is Sunday 234
Generic implementation of custom map transformation
map transformation transforms a type of input into a type of output
Joint generic function implementation of generic classes
package step_six class GenericClassMap<I>(val input: I, val isMap : Boolean = true){ fun <O> map(action:(I)->O) = action(input).takeIf { isMap } } fun main() { println(GenericClassMap("i love this").map { it.uppercase() }) }
Output:
I LOVE THIS
Generic function implementation
private fun <I, O> map(input: I, isMap: Boolean = true, action: (I) -> O) = action(input).takeIf { isMap } fun main() { println(map("into the unknown") { it.uppercase() }) }
Output:
INTO THE UNKNOWN
Type constraint
Similar to Java's t extensions charsequence, Kotlin is written as T: CharSequence.
open class SuperObject(val name: String) open class Human(val humanName: String): SuperObject(humanName) class Man(val manName: String): Human(manName) class Woman(val womanName: String): Human(womanName) class Other(val name: String) fun <T: Human> show(t: T){ // Only Human and subclass objects can be received println("name = ${t.humanName}") } fun main() { // show(SuperObject("super object") / / compilation fails show(Human("human")) show(Man("man")) show(Woman("woman")) // show(Other("other") / / compilation fails }
Output:
name = human name = man name = woman
Generic vararg parameter
vararg is equivalent to a Java variable parameter.
vararg example
fun show(vararg arr: Int){ arr[0] = 1 arr.forEach { println(it) } } fun main() { show(-1) }
Output:
1
Generic vararg
The generic vararg parameter can only be received with the generic parameter array decorated with out. It can only read its elements and cannot be modified.
private fun <T> show(vararg ts: T){ ts.forEach { print("$it ") } } fun main() { show(1, 2, 3) }
Output:
1 2 3
Type judgment
When performing is and as operations on generic parameters, nullable data types should be followed, because generic parameters can receive null.
private fun <T> show(t : T){ if(t is String?){ println(t?.length ?: null) }else if(t is Int?){ println(t ?: null) }else{ println("Other types") } } fun main() { show(null) show("Hope") show(123) show('C') }
Output:
null 4 123 Other types
out and in keywords
out:
out T is equivalent to Java? The difference between extensions T and Java is that out T can only be declared on classes or interfaces.
When out T is declared on a class or interface, all functions of the class can only take T-type variables as return values, not as function input parameters.
in:
in T is equivalent to Java? super T is different from Java in that in T can only be declared on classes or interfaces.
When in T is declared on a class or interface, all functions of the class can only take T-type variables as input parameters, not as function return values.
extend
spread function
The member function of a class defined outside the class can be called like the member function inside the class to access the members inside the class.
class ExpandTest(val info: String) fun ExpandTest.show() = println(info) fun main() { ExpandTest("spread function ").show() }
Output:
spread function
Extended properties
The member properties of a class defined outside the class can be called like the member properties inside the class.
class ExpandField(val info: String) val ExpandField.infoLength get() = info.length fun main() { println(ExpandField("Extended properties").infoLength) }
Output:
4
be careful:
If the access scope of extension functions and extension attributes is not limited, they can be accessed globally.
If you want nullable types to also call extended functions or extended properties, you need to extend nullable types.
Extension functions and extension attributes can be defined in separate files for easy search and maintenance.
Extension to generics
Implementation principle of built-in functions such as apply, let, run, with, also, takeIf and takeUnless.
private fun <T> T.log() = println(this) fun main() { 123.log() "abc".log() 'C'.log() null.log() }
Output:
123 abc C null
Infix: infix expression
infix fun String.infixTest(i: Int){ println("$this:::$i") } fun main() { "abcd" infixTest 1324 }
Output:
abcd:::1324
Use with generics
A wider range of applications, such as to, can generate any type of Pair variable.
private infix fun <T, X> T.union(x: X){ println("t = $this, x = $x") } fun main() { 8734.2 union "abc" }
Output:
t = 8734.2, x = abc
tips: as can be used to alias the guided package, which can improve development efficiency and solve package conflicts.
set operator
map
You can add a collection element to another collection after some transformation.
fun main() { listOf("Beijing", "Shanghai", "Nanjing").map { it.length }.forEach{ print("$it ") } }
Output:
7 8 7
flatMap
Some transformations can be made to the collection elements, and the lambda of flatMap must return a collection.
fun main() { listOf("Zhang San", "Li Si", "Wang Wu").flatMap { listOf("&$it&") }.forEach { print("$it ") } }
Output:
&Zhang San& &Li Si& &Wang Wu&
filter
Select the matching elements according to the filter conditions.
fun main() { listOf("Hi", "Hello", "What", "World", "Happy") .filter {it.contains("H")} .forEach { print("$it ") } }
Output:
Hi Hello Happy
zip
Merge the two sets, encapsulate the corresponding subscript elements into a Pair, and finally put them into a new set.
fun main() { val words = listOf("Hi", "Hello", "Hope", "Happy", "Work") val lengths = listOf(2, 5, 4, 5, 4) words.zip(lengths).forEach { println("word = ${it.first}, length = ${it.second}") } }
Output:
word = Hi, length = 2 word = Hello, length = 5 word = Hope, length = 4 word = Happy, length = 5 word = Work, length = 4
Interoperability with Java
Receive Java data with nullable types
Java code:
package communicate_with_kotlin; public class ProvideValue { public static String getInfo(){ return null; } public static String getString(){ return "test"; } }
Kotlin Code:
import communicate_with_kotlin.ProvideValue fun main() { val info: String? = ProvideValue.getInfo() val string: String? = ProvideValue.getString() println(info?.length ?: "info Is null") println(string?.length ?: "string Is null") }
Output:
info Is null 2
@file:JvmName()
Used to define the class name generated by the Kotlin file, which must be written in front of the package name.
Kotlin Code:
@file:JvmName("NewClassName") package step_six fun jvmName(){ println("test JvmName") }
Java code:
import step_six.NewClassName; public class JvmNameTest { public static void main(String[] args) { NewClassName.jvmName(); } }
Output:
test JvmName
@JvmField
You can make Java code directly access Kotlin variables without using the get method.
Kotlin Code:
package step_six class JvmFieldTest(@JvmField val msg: String)
Java code:
import step_six.JvmFieldTest; public class JvmField { public static void main(String[] args) { System.out.println(new JvmFieldTest("JvmField test").msg); } }
Output:
JvmField test
@JvmOverloads
You can enable Java code to use Kotlin's default parameter feature.
Kotlin Code:
package step_six @JvmOverloads fun show(name: String, age: Int = 99, gender: Char = 'F') { println("name = $name, age = $age, gender = $gender") }
Java code:
package communicate_with_kotlin; import step_six.JvmOverloadsTestKt; public class JvmOverloads { public static void main(String[] args) { JvmOverloadsTestKt.show("ss"); JvmOverloadsTestKt.show("gg", 14); JvmOverloadsTestKt.show("h", 30); } }
Output:
name = ss, age = 99, gender = F name = gg, age = 14, gender = F name = h, age = 30, gender = F
@JavaStatic
Make java code call Kotlin's function like calling Java's static method.
Kotlin Code:
package step_six class JvmStaticTest { companion object{ @JvmStatic fun show(){ println("JvmStatic test") } } }
Java code:
public class JvmStatic { public static void main(String[] args) { JvmStaticTest.show(); } }
Output:
JvmStatic test
Single case
Hungry Han style
object EHanSingleton{ fun show(){ println("Kotlin Hungry Han style single case") } } fun main() { EHanSingleton.show() }
Output:
Kotlin Hungry Han style single case
Lazy style
package step_six class LanHanSingleton private constructor(){ init{ println("The main constructor is executed") } companion object{ val INSTANCE: LanHanSingleton by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED){ LanHanSingleton() } } fun show(){ println("Kotlin Lazy single case") } } fun main() { LanHanSingleton.INSTANCE.show() LanHanSingleton.INSTANCE.show() }
Output:
The main constructor is executed Kotlin Lazy single case Kotlin Lazy single case