I have been learning Kotlin for two years. Since January this year, Kotlin has been put into practical use in the project. I think I am quite proficient in using Kt.

Personally think Kotlin really is a language with more and more bright, but in actual development, initially often appear suddenly forgot a feature or the use of a higher-order functions, and have to go to Google, at this time If there is a note, allows you to search directly to want, so it would be great, this is the role of the notes.


This article is a shortcut to find links, welcome to a key save, download, or search at any time, has been MD format, use Typora enjoy local enjoyment!

  • Youdao Cloud Notes
  • github


This summary is actually a collection of two articles. I learned the first one at the beginning of 2018. After I finished learning it, I was actually in a state of confusion. Of course, relearning is equivalent to picking up and looking at some interesting pages to understand, more is the practical application. So you will find that this note is all based on the early talk, in the middle of the late start into practical use.

Here, a special thanks to Bennyhuo, whose course brought me into Kotlin. It’s wonderful.

Some personal feelings about the books I read:

  • Kotlin Core programming

    From Kotlin’s background to the details of its use, it’s No exaggeration to say it’s a god book.

  • Kotlin programming in action

    Improve the actual development efficiency of a book, if it is mid-term to see, improve may be a lot, if you have actually used Kotlin for a long time, the skills in the article can deepen your understanding, that is, from use into ** oh, ** so it is.

  • In-depth understanding of Kotlin coroutines -bennyhuo’s book

    Not recommended in the early stage, the difficulty is too high, it is possible to look forward to this book into swearing into the monitor under.

Some recommended materials:

  • Kotlin- Chinese documentation

    If anyone says the documentation is bad, I’m sorry to say you missed a cornfield.

  • Kotlin, Google developer:

    That’s good, that’s good, that’s good. I’m kidding. That’s really good.

More and more

Welcome to my notes, CloudBook, which records in detail what I have learned and experienced.

As a developer, it’s essential to keep the habit of learning. We can’t change the direction of The Times, but at least don’t be far behind, we may not be able to change our education, family, but the future is up to us. Always be a learner and always keep a love of technology.

I can only take a few of them here, because the word limit is limited.

Kotlin’s path to learning

What is Kotlin? The Kotlin Study Guide

Kotlin is a static language that runs on the JAVA Virtual Machine, Android, and browsers. It is 100% JAVA compatible. If you are familiar with JAVA, you will find that Kotlin mostly uses the classic JAVA collections framework in addition to its own title library. Learning Objectives 1. Learn to use Kotlin 2. Understand the implementation behind some of the featuresCopy the code

The data type for Kotlin

Var is a variable and val is a read-only variable. Val must be initialized when it is created, just like final in Java.Copy the code

1. Understand basic types. 2. Understand classes and related concepts

Basic types of

  1. Boolean

    Var a: Boolean=true var b: Boolean=false A is the parameterCopy the code
  2. Number

    var a: Int =8
    var a: Int =0xFF
    Copy the code
  3. Float

    Type Float must be followed by F NaN/not a number val f1: Float =8.0F val Positive: POSITIVE_INFINITY val Negative Float.NEGATIVE_INFINITY minus infinityCopy the code
  4. Short Short integer

  5. Byte

Unpacking and Chart data types

Int anInt = 5 Integer anInteger = 5 in Kotlin, anInt is actually a combination of anInt and anInteger, and the compiler will do that for us if necessary.Copy the code

Basic data type conversions and strings

In Kotlin, call toLong() val anInt: Int =5 val aLong: Long = abint.tolong () val aLong: Long = abint.tolong ()Copy the code
Comparison between strings
== Compare content, that is, similar to Java equals === compare objects are the sameCopy the code
Concatenation of strings
  	// String template $
  	val a: Int = 1
    val b: Int = 2
    println("" + a + "+" + b + "=" + (a + b))
    println("$a+$b=${a+b}"If you want to add double quotes to a string, add the escape character Petterp"123"var string:String="Petterp \"123\""The $sign needs to be printedvar money:String="1000"
    println("$$money"TrimIndent () removes the empty left side of the string. Escapes cannot be used in thisvar raw:String="" "456 "123" ".trimIndent()
Copy the code

Classes and objects

  1. The class method
    • Class class name {member}
  2. What is an object
    • Is a concrete concept, as opposed to a class
    • Describe specific individuals of a species
  3. The relationship between classes and objects
    • A class can usually have many concrete objects
    • An object can only belong to one class by nature
    • That is, the relationship between the object and the class is 1.. n
    • Objects are also often referred to as objects of a class or instances of a class
  4. Class inheritance
    • Extracting commonalities from multiple classes leads to a more abstract class, the superclass
    • A child class has all the characteristics of its parent class
    • Subclasses can also customize their own characteristics
    • All classes ultimately inherit from Any
// An example of inheritance
/*open allows the inherited main constructor to contain no code. The initialization code can be placed in initializerblocks prefixed with the init keyword. During instance initialization, initialization blocks are executed in the order in which they appear in the class body, interwoven with the property initializer: */
//constructor the main constructor

class demo1 constructor(a: String, b: String) : Demo(a, b)
class demo2 constructor(a: String, b: String) : Demo(a, b)

open class Demo (a: String,b: String) {
    init {
    	// Get the name of the class
        println("${this.javaClass.simpleName} $a $b")}}fun main(args: Array<String>) {
    var dd1: demo2 = demo2("a"."b")}openOverride methods also need to be addedoverrideSubclass overrides need to addCopy the code

Empty type and intelligent type conversions

  1. Empty type
    • / /? If null, execute the first half, otherwise execute the second half print length
    • / /!!!!! Enforces the compiler to ignore empty type safety
Java codepublic class MyClass {
       public static void main(String[] a){
       public static String demo(){
           return null; }} Kotlin codefun demo(a): String? {
       // If you add? The compiler will allow null to be returned, otherwise an error will be reported
       return null
   fun main(args: Array<String>) {
       / /? If null, execute the first half, otherwise execute the second half print lengthprintln(demo()? .length)val a: String? = "123"
       / /!!!!! Tells the compiler to allow the compiler to ignore empty type safetyprintln(a!! .length) }Copy the code
  1. Secure type conversions
// The parent class is strongly converted to a subclass test
// Chaid is inherited from Parent

public class Test {
    public static void main(String[] args) {
        Parent parent=new Parent();
        ((Chaid) parent).pp();

fun main(args: Array<String>) {
    // The parent class is strongly converted to a subclass test
    val parent: Parent = Parent()
    // If parent fails to convert, null is returned and the program does not crash
    val chaid: Chaid? = parent as? Chaid
    // In this case, the print is null
Copy the code


  • A mathematical concept that represents a range
  • IntRanage is the most commonly used subclass of ColsedRange
  • Basic writing
    • 0.. Said 100 [0100]
    • 0 until 100 indicates [0,100]
    • i in 1.. 100 determine whether I is in the interval [0,100]
fun main(args: Array<String>) {
    val range:IntRange=0.1024.      / / 0102 [4]
    val ranege_exclusive:IntRange=0 until 1024  / / [0102 4)
    val range_min:IntRange= 0.. -1
    // Check whether it is empty

    // Check whether 1024 is included
    // Contains: contains: contains: contains: contains
    println(1024 in range)

    // Iterate -- equivalent to output the range array
    for (i in range){
        print("$i,")}}Copy the code

How to use an array

In Kotlin, arrays of basic types are customized to avoid unnecessary packing and unpacking and to save efficiency

  • Basic writing

    val array: Array = arrayOf(…)

  • Basic operation

    • Print array[I] Prints the ith member
    • Array [I] = “Hello”
    • Array. size Specifies the length of the array
val arrayOfInt: IntArray = intArrayOf(1.3.5)
val arrayOfChar: CharArray = charArrayOf('H'.'e'.'l'.'l'.'o')
val arrayOfString: Array<String> = arrayOf("Petterp"."p")
fun main(args: Array<String>) {
    / / for iteration
    for (int in arrayOfInt) {
    // return the elements of the range [0,2)
    println(arrayOfString.slice(0 until 2))
    // Create a string using a delimiter
    // Converts characters from the specified array to a string
    // Print the full name of the class
    // Print the class name range
    println( until 2))
    // Basic type conversion
    val hello:Long= arrayOfChar.size.toLong()

class Kotlin2 {}Copy the code

Program structure

Constants and variables

  • Val declares a constant, similar to the Java final keyword, and cannot be repeatedly assigned
  • In Kotlin we have type derivation, the compiler can derive the type of a quantity, so you can derive a type definition without having to write a data type,
  • The runtime constant val x=getX() can be modified using reflection
  • The compiler constant, const val x=1, has been defined during the code writing process, and wherever it is referenced in the code, it is replaced by x, as you can see in the bytecode
  • Var var
val data: String = "Petterp"
val data2 = data
// Type derivation, which the compiler already knows is of type Int
val data3 = 1
fun main(args: Array<String>) {
Copy the code
Now addconst 

const val data: String = "Petterp"
const val data2 = data
// Type derivation, which the compiler already knows is of type Int
val data3 = 1
fun main(args: Array<String>) {
Copy the code

So that’s what the compiler constant is for. References to compiler constants directly indicate the value of the variable


// Function
fun Demo1(a: Int): Int {
    return a
// When a function returns the value of an expression
fun Demo2(a: Int) = a

// An anonymous function that needs to be assigned to a function variable
val k = fun(a: Int): Int {
    return a

fun main(args: Array<String>) {
    println(k(300))}Copy the code

Matters needing attention

  • Single function
  • The name of the function should be what the name suggests
  • Don’t have too many parameters

Lambda expressions (very important)

  1. What is a Lambda expression

    • Lambda is actually an anonymous function
    • {[argument list] -> [function body, last line is return value]}
    • Val sum= {a: Int, b: Int -> a+b}
  2. Lambda type representation

    • () -> Unit No parameter. The return value is Unit
    • (Int) -> Int // return an integer
    • (String, (String) ->String) ->Boolean // Pass a String, a Lambda expression, and return Boolean
  3. Calls to Lambda expressions

    • Call with ()

    • Equivalent to the invoke ()

    • For example,val sum{a:Int,b:Int-> a+b}1.2) the sum. Invoke (1.2)
      Copy the code
  4. Simplification of Lambda expressions

    • The last Lambda can be moved out when a function argument is called
    • The function argument has only one Lambda, and the parentheses can be omitted when called
    • Only one argument to Lambda can default to it
    • A function that returns a value consistent with its parameter can be passed in as a function reference
    // The original
    args.forEach ({ println(it) })
    // For functions, if the last argument is a Lambda expression, the parentheses can be moved outside
    args.forEach(){ println(it) }
    // If there is nothing in the parentheses, delete the parentheses
    args.forEach { println(it)}
    // If you pass a function of the same type as the Lambda expression you want to receive, simplify it further
    args.forEach (::println)
    Copy the code

Class members (member methods, member variables)

  1. What is a class member

    • Properties: or member variables, variables within the scope of the class
    • Methods: Member functions, class-scoped functions
  2. The difference between functions and methods

    • Functions emphasize functionality, regardless of dependencies
    • Methods are usually called from a class perspective
  3. Define methods

    It's written exactly the same as an ordinary functionclass A {
        // The return value type is not returned
        fun say(name: String) = println("Hello $name")
        fun phone(phone:String):String{
           return phone
    Copy the code
  4. Custom properties

    • Constructor parameters with val/var are all attributes

    • Properties can also be defined inside a class

    • // B is a common constructor parameter
      class A(val a: Int, b: Int) {
          var b = 0
      Copy the code
  5. Attribute access control

    • Property can define getSet/setter

    • class B{
          // An immutable set method modified by val
          val demo:Int=0
       /* set(value) { }*/
          var demo2:Int=0
          set(value) {
              field = value
      Copy the code
  6. Property initialization

    • The initialization of the property is done as much as possible in the constructor

    • Unable to initialize in constructor, attempt to degrade to local variable

    • Var is lateinit and val is lazy

    • Nullable types are carefully initialized with null directly

    • class X
      class A(val a: Int, b: Int) {
          var b = 0
          // Laterinit Delays initialization
          lateinit var c: String
          lateinit var d: X
          val e: X by lazy {
              println("Start X")
          var cc: String? = null	// This is not recommended
      Copy the code

Basic operator

  • Any class can define or override the base operators of its parent class

  • Defined by the named function corresponding to the operator

  • The number of parameters is required, but the type of parameters and return value is not required

  • You cannot define arbitrary operators, as Scala does

    // Use the operator keyword to override the base operator. For example, the following plus function plus operator is equivalent to the + in the base operation
    // Operator overloading is required to correspond to the operator's function name. For example, to overload addition, the function name must be plus
    class Complex(var real:Int.var imaginzry:Int) {operator fun plus(other:Complex):Complex{
            return Complex(real+other.real,imaginzry+other.imaginzry)
        operator fun plus(other: Int):Complex{
            return Complex(real+other,imaginzry)
        operator fun  plus(other: Any):Int{
           return real.toInt()
        override fun toString(a): String {
            return "$real+$imaginzry"}}class Book{
        //infix refers to an expression that is not called by parentheses
        infix fun on(any:Any):Boolean{
            return false}}class Desk
    fun main(args: Array<String>) {
        val c1=Complex(3.4)
        val c2=Complex(1.2)
        //-name <Name>
        // In for this element returns 1 otherwise returns -1
        if ("-name" in args){
            println(args[args.indexOf("-name") +1])}}Copy the code


  1. Infix expression

    • A function that takes only one argument and is decorated with infix

    • // Functions defined by infix (infix expression) need not be called as. Xx (), but can be called by the function name (without parentheses). This notation is common in DSLS and should be used with caution in your code to affect readability
      class Book{
          infix fun on(any:Any):Boolean{
              return false}}class Desk
      fun main(args: Array<String>) {
          if(Book() on Desk()){
      Copy the code
  2. If expression

    • if .. Else is just like Java, but Kotlin has a return value, so it’s called an expression

    • Expressions and completeness (that is, all conditions must be complete when assigning with an if expression)

    • val x=if(b<0) 0 else b
      val x=if(b<0) 0 // Error, the branch must be complete when assigning
      Copy the code
  3. When the expression

    • Enhanced switch, support any type

    • Support for spring expression conditional branching (like if)

    • Expression and completeness

    • fun main(args: Array<String>) {
          val x=99
          val b=when(x){
              in 1.100. ->  10
              !in  1.100. -> 20
              args[0].toInt() -> 30
              else -> x
              in 1.100. -> println("ok")
              else -> println("no")}// val mode=when{
      // args.isNotEmpty()&& args[0]=="1" ->1
      // else ->0
      / /}
      Copy the code

The for loop

fun main(args: Array<String>) {
    for((i,value) in args.withIndex()){
        println("$i  -> $value")}for(i in args.withIndex()){
        println("${i.index} -> ${i.value}")}}Copy the code

Exception handling

  1. try… catch

    • Catch branch matches the exception type

    • You can write it as an expression to assign a value

    • val  a=try {
          }catch (e:Exception){
      Copy the code
  2. finally

    • Finallu executes whether or not the code throws an exception

    • // Note that finaly is executed first and return is performed last
       fun  P(a): Int {
          / / try expression
          return try {
              100 / 10
          } catch (e: Exception) {
          } finally {
              println("I'll print first.")}Copy the code

Named parameters, variable-length parameters, default parameters

  1. Named parameters

    • Attach a parameter to the function’s argument

    • // In this case, the position of the parameter does not matter
      fun main(args: Array<String>) {
          sum(b=1,a=2)}fun sum(a: Int, b: Int) {
          println("a=$a b=$b")}Copy the code
  2. Variable-length argument

    • A parameter can accept multiple values

    • It may not be the last parameter

    • If there is ambiguity in passing parameters, you need to use named parameters

    • fun main(vararg: Array<String>) {
          sum(, b = "B")}fun sum(vararg a: Int, b: String) {
      Copy the code
  3. Spread Operator

    • Expansion of only arrays is supported

    • Only arguments for variable-length argument lists

    • Cannot be overloaded

    • It’s not a normal operator

    • fun main(vararg: Array<String>) {
          sum(, b = "B")
          //Spread Operator. Only arrays are supported
          val array= intArrayOf(
          sum(*array,b="B")}fun sum(vararg a: Int, b: String) {
      Copy the code
  4. The default parameters

    • Specify default values for function arguments

    • Default values can be specified for arguments in any location

    • When passing parameters, if there is ambiguity, you need to use named parameters

    • fun main(vararg: Array<String>) {
          // The caller does not pass the value, and uses the default value
          sum(1."B")}// If a function uses a value frequently, specify that value when declaring it
      fun sum(a: Int = 0, b: String) {
          println("a=$a  b=$b")}Copy the code


Abstract classes and interfaces

  1. What is an interface

    • An interface, intuitively understood, is a convention

    • interface A {
          fun Print(a)
      // Interface inheritance
      interface A1 : A {
          // You can also define a variable, which actually corresponds to a method, but you can't have a set, get method
          var a: Int
          fun ko(a) {
      class TestA(override var a: Int) : A1 {
          override fun Print(a) {
              println("Petterp")}}fun main(a) {
          val test = TestA(1)
      Copy the code
  2. interface

    • The interface cannot be stateful
    • It must be implemented and used by the class
  3. An abstract class

    • A semi-finished product that implements part of the protocol

    • You can have a state, you can have a method

    • Must be inherited by a subclass

    • interface P1
      interface P2 : P1
      abstract class A {
          // Print the class name
          fun Print(a) = println(javaClass.simpleName)
      class B : A(), P2
      fun main(a) {
          // This cannot be used because there is no subclass inheritance
      // val a = A
          // The relationship can be written like this
          val p1: P1 = B()
          val p2: P2 = B()
          val a: A = B()
          val b: B = B()
      Copy the code
  4. Commonalities between abstract classes and interfaces

    • It is abstract and cannot be instantiated directly
    • There are methods that need to be implemented by subclasses (implementation classes)
    • A parent (interface) variable can be assigned to an instance of a subclass (implementation)
  5. The difference between abstract classes and interfaces

    • Abstract classes are stateful, interfaces are not
    • Abstract classes have method implementations, and interfaces can only have stateless default implementations
    • Abstract class can only be single inheritance, interface can be implemented more
    • Abstract class reflects essence, interface reflects capability


  • A parent class needs to be open to be inherited

  • The superclass method whose attribute needs to be open to be overridden

  • Interfaces, interface methods, and abstract classes default to Open

  • Overriding a parent (interface) member requires the onVerride keyword

  • class D:A() , B ,C
    Copy the code
  • Notice that inheriting a class actually calls the superclass constructor

  • Classes can only be single inheritance, interfaces can be multiple implementations

  • // Override the Demo of the parent class
    abstract class Person(open val age: Int) {
        abstract fun work(a)
    class MaNong(age: Int) : Person(age) {
        // Override the attribute
        override val age:Int
        get() = 0
        override fun work(a) {
            println("I'm a coder.")}}class Doctor(age: Int) : Person(age) {
        override fun work(a) {
            println("I'm a doctor")}}fun main(a) {
        val manong = MaNong(20)
        val doctor = Doctor(100)
    Copy the code
  • The interface agent

  • The implementation of interface methods is handed over to the proxy class

  • class Manager(driver:Driver):Driver by driver
    // Demo of the interface proxy
    interface AA{
        fun Print1(a)
    interface BB{
        fun Print2(a)
    class Car:AA{
        override fun Print1(a) {
            println("AA")}}class Bar:BB{
        override fun Print2(a) {
    //class AB:AA,BB{
    // override fun Print1() {
    // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    / /}
    // override fun Print2() {
    // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    / /}
    / /}
    //by Interface proxy
    class SendWill(val aa:AA,val bb:BB):AA by aa,BB by bb
    fun main(a) {
        val aa=Car()
        val bb=Bar()
        val send=SendWill(aa,bb)
    Copy the code
  • Interface method conflict

  • Interface methods can have default implementations

  • The signature is consistent and the return value is the same

  • Subclasses (implementation classes) must override conflicting methods

  • Super <[superclass (interface) name]>.[method name]([parameter list]Copy the code
  • Demo
    interface A {
        fun setT(a) = "Interface is A"
    interface B {
        fun setT(a) = Interface "B"
    abstract class C {
        open fun setT(a) = "Abstract class C"
    class Demo(val a: Int) : A, B, C() {
        override fun setT(a): String {
            return when (a) {
                1 -> super<A>.setT()
                2 -> super<B>.setT()
                3 -> super<C>.setT()
                else -> ""}}}fun main(a) {
    Copy the code

Class and its members visibility

Object(the simplest singleton pattern)

  • A class that has only one instance

  • Cannot customize the constructor

  • Can implement the interface, inherited from the parent class

  • This is essentially the most basic implementation of the singleton pattern

  • Koltin--
    interface A {
        fun a1(a)
    abstract class C
    object KotlinDan : C(a), A {
        override fun a1(a) {
    public class Kotlin_java {
        public static void main(String[] args) {
            // Reference the Kotlin code
            // In JavaJavaDan.inter.Ag(); }}// Simple singleton example in Java
     class JavaDan{
        static JavaDan inter=new JavaDan();
        private JavaDan(a){}
        void Ag(a){
            System.out.println("Java"); }}Copy the code

Associated objects and static members

  • Each class can correspond to a companion object

  • Members of companion objects are globally unique (for classes)

  • The members of a companion object are similar to Java static members

  • In Kotlin, consider replacing static members with package-level functions and package-level variables

  • Use of JvmField and JvmStatic

  • Kotlin--
    class Demo private constructor(val value:Double) {// Companion object
        companion object {
            fun A(double: Double): Demo {
                return Demo(double)
            val TAG:String="Petterp"}}fun main(a) {
    public class KotlinJava {
        public static void main(String[] args) {
            // Java code with @jVMStataic and JvmField not added
            Demo demo = Demo.Companion.A(1.1);
            String tag = Demo.Companion.getTAG();
            / / add after
            Demo demo1 = Demo.A(1.1); String tag1=Demo.TAG; }}Copy the code

Method overloading with default parameters

  1. Method overloading

    • Overloads

    • Methods with the same name but different parameters

    • Jvm function signature concept: function name, parameter list

    • It has nothing to do with the return value

    • class A{
          fun a(a):Int{
              return 0
          fun a(int: Int):Int{
              return int
          // Method overloading is independent of the return value
         /* fun a():String{ }*/
      fun main(a) {
          val a=A().a()
          val a2=A().a(123)}Copy the code
  2. The default parameters

    • Set a default value for the function argument

    • You can set default values for parameters anywhere

    • Tool name parameter when a function call generates confusion

    • Kotlin--
      class A {
      // fun a():Int{
      // return 0
      / /}
      // fun a(int: Int):Int{
      // return int
      / /}
          // Use named arguments instead of the overloaded methods above
          fun a(int: Int = 0): Int {
              return int
      fun main(a) {
          val a = A().a()
          val a2 = A().a(123)} Java call --public class KotlinJava {
          public static void main(String[] args) {
              A a=new A();
              // Add @jvmoverloads to the Kotlin code to get Java to recognize the named parameter
              a.a(123); }}Copy the code
  3. The relationship between method overloading and default parameters

    • The correlation between the two and @jvmoverloads

    • Avoid defining unimportant overloads

    • Bad design, for example:

      A Bug in the Java codepublic class Bug {
          public static void main(String[] args) {
              List<Integer> list=new ArrayList<>();
              // The array is out of bounds
              list.remove(2); }} in the Kotlin codefun main(a) {
          val list = ArrayList<Int>()
          list.remove(2)}Copy the code

Extension members

  • Add methods, attributes to existing classes

  • fun X.y():Z {... } val X.m notice that the extended attribute cannot be initialized. It is similar to the interface attributeCopy the code
  • Java calls to extension members are similar to calls to static methods

  • operator fun String.times(int: Int):String{
        val stringBuilder=StringBuilder()
        for (i in 0 until  int){
            stringBuilder.append(this)}return stringBuilder.toString()
    val String.op:String
        get() = "123"
    fun main(a) {
        // The extension method is prefixed with operator
        println("abc".op)} Java callspublic class A {
        public static void main(String[] args) {
            System.out.println(Kotlin2Kt.getOp("Petterp")); }}Copy the code

The property broker

  • Define methods

    val/var <property name>: <Type> by <experession> 
    // Translate property- property type- type experssion- function call
    Copy the code
  • The agent needs to implement the corresponding setValue/getValue method

  • // Demo--
    class A{
        val p1:String by lazy {
        // Property broker, which actually calls getValue
        val p2 by X()
        // Need to implement setValue
        var p3 by X()
    class X{
        private var value: String? =null
        operator fun getValue(thisRef:Any? ,property:KProperty< * >):String{
           returnvalue? :""
        operator fun setValue(thisRef: Any? ,property:KProperty<*>,string: String){
    fun main(a) {
        val a=A()
        // This is null because no value has been set
    Copy the code

Data classes

  • Goodbye, JavaBean

  • The default implementation of copy,toString and other methods

  • ComponentN method

  • AllOpen and noArg plug-ins (as a matter of design, the data class does not allow subclasses, so if you want to rewrite, you will need to use these plug-ins. Bytecode changes at compile time will remove the final keyword and add a no-parameter constructor)

  • When a data class is initialized, it must assign values (with arguments) to its attributes, that is, it does not have a default parameterless constructor

  • // After the data is added, the various methods are automatically implemented, and the bytecode discovery can be viewed
    data class A(val id:Int.val name:String)
    class ComponentX{
        // Implement component1() manually
        operator fun component1(a):String{
            return "PP"
        operator fun component2(a):Int{
            return 0}}fun main(a) {
        val (a,b)=ComponentX()
        // Print the result
        /*A(id=1, name=Petterp) a=PP,b=0*/
    Copy the code
    AllOpen noArg Indicates the configuration methodCopy the code

The Inner class (this @ Outter, this @ Inner)

  1. The inner class

    • A class defined within a class

    • Access control similar to class members

    • The default is a static inner class; non-static uses the inner keyword

    • The usage of this@Outter, this@Inner

    • Use a non-static inner class if the inner class depends on the outer class, or vice versa

    • class A {
          var int:Int = 5
          // Add inner to non-static inner class
          inner class A1 {
              var int:Int = 10
              fun Print(a){
                  // Inner class variables
                  // External variables
      Copy the code
  2. Anonymous inner class

    • Inner class with no name defined

    • Class name generated at compile time, similar to Outter$1.class (appears to have no name, but actually has its own Id at compile time)

    • Can inherit the parent class, the implementation of multiple interfaces, and Java notice the difference

      interface OnclickListener {
          fun onclick(a)
      class View {
          var onclickListener: OnclickListener? = null
      open class A
      fun main(a) {
          val view=View()
          view.onclickListener=object : A(),OnclickListener{
              override fun onclick(a){}}}Copy the code

The enumeration

  • Classes with countable instances. Note that enumerations are also classes

  • You can modify the construct to add members

  • It can improve the code’s expressiveness, but also has a performance overhead

  • // Enumeration classes also have constructors. We can pass arguments to their constructors
    enum class LogLevel(val id:Int){
        A(1),B(2),C(3),D(4),E(5);// The semicolon is required
        fun getTag(a):String{
            return "$id.$name"
        override fun toString(a): String {
            return "$name.$ordinal"}}//LogLevel is more like the syntactic sugar of LogLevel2
    // The two are equivalent
    class LogLevel2(val id:Int) private constructor() {// Associated object writing
        companion object {
            val A=LogLevel2(1)
            val B=LogLevel2(2)
            val C=LogLevel2(3)
            val D=LogLevel2(4)
            val E=LogLevel2(5)}constructor(i: Int) : this()}fun main(a) {
        // Iterate through the enumeration, overriding the toString() method
        // Return an instance of "A"
        println(LogLevel.valueOf("A"))}Copy the code

Sealed Class

  • Subclasses are countable (enumerations are instances countable)

  • To note the difference between sealed classes and enumerations, see the following Demo

  • // In the following Demo, this is a music playing Demo
    // We can use enumerations where we need different instructions and no parameters, but we cannot use enumerations where we need different instructions and no parameters
    Subclasses of sealed can only inherit from the same file as sealed, or as its inner class
    sealed class PlayerCmd {
        class Play(val yrl: String, val postition: Long = 0) : PlayerCmd()
        class Seek(val postition: Long) : PlayerCmd()
        object Pause : PlayerCmd()
        object Resume : PlayerCmd()
        object Stop : PlayerCmd()
    enum class PlayerState{
    Copy the code

Higher-order functions

The basic concept of higher order functions

  • A function that passes or returns a function

  • Function reference ::println

  • With Receiver reference, pdfPrinter :: println

    fun main(args: Array<String>) {
        // Package level function reference
        / / class reference
        val helloWorld = Hello::world
    // args.filter(String::isNotEmpty)
        // The caller references the method
    class Hello {
        fun world(a){
            println("123")}}class PdfPrinter {
        fun println(any: Any) {
    fun getRest(s1:String):String="Petterp $s1"
    fun demo(a: String, method: (s1: String) - >String): String = method(a)
    fun demo2(methoud2:()->Unit)=methoud2()
    Copy the code

Commonly used higher order functions

  • ForEach (usually used to traverse collections)

     val list = listOf(
        val newList=ArrayList<Int>()
        list.forEach {
    Copy the code
  • Map (for collection mapping, but also for collection transformation)

      val list = listOf(
      val newList = { it * 2 + 3 }
    Copy the code
  • Flatmap (used to flaten the set of a set into a set. Transformations can be performed in combination with a map)

    fun main(a) {
      .flatMap { intRange ->
   { intElement ->
        / / short
        list.flatMap { 
   { "No.$it" }
    Copy the code
  • Fold (used to sum and add an initial value because fold, unlike map, has no strict restrictions on initial values, so fold can also be typed)

    fun main(a) {
        / / traverse 0.. 6 the factorial
        // Add the initial value 5. The result is 879
        println((0.6.).map(::factorial).fold(5){acc, i ->acc+i})
        / / plus the psotion
        println((0.6.).map(::factorial).foldIndexed(StringBuilder()){postion,acc, i ->acc.append("$i-$postion,")})
        // change return type result 1,1,2,6,24,120,720,
        println((0.6.).map(::factorial).fold(StringBuilder()){acc, i -> acc.append("$i,")})/ / reverse
        println((0.6.).map(::factorial).foldRight(StringBuilder()){i,acc -> acc.append(i).append(",")})// String concatenation
        println((0.6.).joinToString(","))}/ / factorial
    fun factorial(n:Int):Int{
        if (n==0) {return 1
        return (1..n).reduce { acc, i -> acc*i}
    Copy the code
  • Reduce (sum)

    fun main(a) {
        val list = listOf(
        // Summation result: 9655
        println(list.flatMap { it }.reduce { acc, i -> acc + i })
    Copy the code
  • Filter (used for filtering, reserved if the passed expression value is true)

     val list = listOf(
        // If the expression is true, keep it
        println(list.filter { it%2= =0 })
        // Meet the conditions of reservation and have their place
        println(list.filterIndexed{index, i ->  i%2= =1 })
    Copy the code
  • Take (usually loop traversal with conditions)

      val list = listOf(
      	// Start with the first element and return only the elements that match
        println(list.takeWhile { it%2= =1 })
        // Start with the last element and return the previous element until the last one does not match
        println(list.takeLastWhile { it%2= =0})
        // Return the last element in the list at the specified element position, without the element at the specified position
        // Return the first element in the list at the specified element location, excluding the specified element location
        // The parameter is a method and the return value is a Boolean type. If true, the object T is returned, otherwise null is returned
        println(list.takeIf { it.size>6 })
    Copy the code
  • Let,apply,with,use (to simplify code,use can simplify the use of colse,try/catch templates)

    data class Person(val name: String, val age: Int) {
        fun work(a) {
            println("I am$name")}}fun main(a){ findPerson()? .let { println(it.age) }// Apply is equivalent to an extension methodfindPerson()? .apply { work() println(age) } BufferedReader(FileReader("A.txt")).use {
            var line:String?
            while (true){ line=it.readLine()? :break
    // val br=BufferedReader(FileReader("hello.txt")).readLine()
    fun findPerson(a): Person? {
        return null
    Copy the code

Tail recursive optimization

Tail recursion is when a function calls itself without any operations, i.e. all recursive calls to a function occur at the end of the function. Tail recursion can be optimized using the tailrec keyword

  • A special form of recursion

  • There is no other operation after calling itself

  • The talrec keyword indicates compiler tail recursive optimization

  • Tail recursion can be converted directly to iteration

  • data class ListNode(val value:Int.varnext:ListNode? =null)
     tailrec fun findListNode(head:ListNode? ,value:Int):ListNode? { head? :return null
        if (head.value==value) return head
        return findListNode(,value)
    fun main(a) {
        val Max_Node_Court=1000000
        val head=ListNode(0)
        var p=head
        for (i in 1..Max_Node_Court){
        println(findListNode(head,Max_Node_Court-2)? .value) }fun factorial(n:Long):Long{
        return n* factorial(n-1)}data class TreeNode(val value:Int) {varleft:TreeNode? =null
        varright:TreeNode? =null
     fun findTreNode(root:TreeNode? ,value:Int):TreeNode? { root? :return  null
        if (root.value==value) return root
        returnfindTreNode(root.left,value)? :return findTreNode(root.right,value)
    Copy the code


  • The environment in which the function runs

  • It holds the state in which the function runs

  • Functions can be defined inside functions

  • Classes can also be defined inside functions

  • val String="HelloWord"
    //Lambda returns a function with no arguments
    fun makeFun(a): () - >Unit{
        var count=0
        return fun (a){
    fun main(args: Array<String>) {
    // val x= makeFun()
    // x()
    // x()
        val add5= add(5)
        for (i in fibonac()){
            if (i>100) break
    fun fibonac(a):Iterable<Long> {var first=0L
        var second=1L
        return Iterable {
            object :LongIterator(){
                override fun hasNext(a)=true
                override fun nextLong(a): Long {
                        val result=second
                        return result
    / / short
    fun add(x:Int)=fun (y:Int)=x+y
    / / complete
    fun add2(x: Int): (Int) - >Int{
        return fun (y:Int):Int{
            return x+y
    Copy the code

Function of composite

  • f(g(x))

    val add5={i:Int -> i+5}     //f(g(x))
    val mulyiplyBy2={i:Int ->i*2} // m(x)=f(g(x))
    fun main(args: Array<String>) {
        println(mulyiplyBy2(add5(8)))       / / (5 + 8) * 2
        val k= add5 andThen mulyiplyBy2
        println(k(8))}AddThen is the infix expression Function
              P1 is the parameter type,P2 is the return value type */
    infix  fun <P1,P2,R > Function1<P1,P2>.andThen(function: Function1<P2,R>):Function1<P1,R>{
        return fun (p1:P1):R{
            // Return a function, and the function is called again
            // Call the function again, passing its return value to the function
            return function.invoke(this.invoke(p1))
    infix  fun <P1,P2,R> Function1<P1,P2>.compose(function: Function1<P2,R>):Function1<P1,R>{
        return fun (p1:P1):R
            return function.invoke(this.invoke(p1))
    Copy the code


  • Currying simply means that a function of several variables is transformed into a call chain of a function of one variable

  • // Change from multi-parameter to single-parameter
    fun Test(a: Int): (String) -> (Int) - >Boolean {
        return fun(b: String): (c: Int) - >Boolean {
            return fun(c: Int): Boolean {
                return true}}}fun log(tag: String, target: OutputStream, message: Any?). {
        target.write("[$tag] $message\n".toByteArray())
    / / curry
    fun log2(tag: String)
            = fun(target: OutputStream)
            = fun(message: Any?).
            = target.write("[$tag] $message\n".toByteArray())
    fun main(a) {
        log2("Petterp")(System.out) ("Demo")
        ::log.curried()("Petterp")(System.out) ("Demo")}fun <P1,P2,P3,R> Function3<P1,P2,P3,R>.curried(a)
        =fun(p1:P1)=fun (p2:P2)=fun (p3:P3)=this(p1,p2,p3)
    Copy the code

Partial function

  • A new function obtained by passing some of the parameters

  • For some values of fixed parameters, partial function can bind it, and then generate a new function, and the new function in addition to only need to have the binding parameters of parameter values, of course you also can be regarded as the default parameters + named the way to realize the parameter is fixed, if need the parameters of the fixed in the middle, although that can be addressed by a named parameter, But it was awkward because you had to use a large number of named parameters, so the partial function was born

  • val test=fun(name:String,love:String):String{
        return "${name}love$love"
    fun <P1,P2,R> Function2<P1,P2,R>.partial1(p1:P1)=fun(p2:P2)=this(p1,p2)
    fun <P1,P2,R> Function2<P1,P2,R>.partial2(p2:P2)=fun (p1:P1)=this(p1,p2)
    fun main(a) {
        val t= test.partial1("Petterp")
        println(t("Write a Bug"))
        val t2= test.partial2(Change "Bug")
        println(t2("Petterp"))}Copy the code

The generic

Basic syntax for generics

  • A generic type or abstraction of a type
  • Duck typing is an object inference subcategory for both dynamic typing and static languages. In duck typing, the focus is not on the type of the object itself, but on how it is used, that is, we only care about its behavior.

Java interoperates with Kotlin

Basic interoperability

  1. Empty safety type

    • Kotlin null security type principle

      When Kotlin is compiled, it adds a function call that checks for null parameter types and return value typesCopy the code
    • PlatFromType

      Since Java does not have an empty safety type, there may be a platform type issue, where we developers need to know whether the parameters we need to use can be nullCopy the code
    • @ @ NotNull and Nullable

      This can be remedied by annotations when Java code is developedCopy the code
  2. Several types of function calls

    • Package-level functions: static methods

      There is no such function in Java. At compile time, it generates a class for Kotlin that contains all the package-level functions. In Java's view, these are static methods, so when Java calls them, they are called staticallyCopy the code
    • Extension method: Static method with Receiver

      The extension method simply adds a Receiver as an argumentCopy the code
    • Operator overload: static method with corresponding name of Receiver

  3. The use of common annotations

    • @jVMfield: Compiles properties into JAVA variables

    • JvmStataic: Compile an object’s methods into Java static methods

    • JvmOverloads: Default arguments generate overloaded methods

      If a parameter has a default parameter, Java is actually invisibleCopy the code
    • @file: JvmName: Specifies the compiled class name of the Kotlin file

  4. NoArg and AllOpen

    • NoArg generates a parameterless construct for the annotated class

      Supports Jpa annotations, such as @EntityCopy the code
    • AllOpen removes final for annotated classes, allowing inheritance

      Support for Spring annotations, such as @ComponentCopy the code
    • Support custom annotation types, such as @poko

  5. The generic

    • The wildcard Kotlin * corresponds to the Java?

    • Covariant and contravariant out/in

      ArrayList<out String>
      Copy the code
    • No Raw type

      List-> Kotlin List<*>Copy the code

Kotlin- Refactoring – closer to the real world

Classes and interfaces

Define an interface

// Define an interface
interface SimpleInter {
    fun test(a)
    val number: Int
Copy the code

Defining a class

// Open means that inheritance is allowed. In Kotlin, inheritance and override are not allowed between classes and methods by default (excluding abstract classes).
open class SimpleClass{
		open fun put(a)
Copy the code

Inheritance between classes and implementing an interface

// Implement the parameters in the interface
class Test1(override val number: Int) :SimpleClass(),SimpleInter{
    // Interface method
    override fun test(a){}// Override the superclass method
    override fun openTest(a) {

Copy the code

Custom set, a get

// In kotlin, the set and get methods are added by default
class ClassTest1(override val number: Int) : SimpleInter {
    override fun test(a){}var money = number
        get() {
            return field
        set(value) {
            field = value

Copy the code

Class instantiation and property invocation

val number=Test1::number

// Attribute call
val classTest=ClassTest1(123)
val money=classTest::money
Copy the code

Extension methods

class Book{}// Define extension methods for the Book class
fun Book.noBook(a){}// You can also define extended attributes
// Backing Field
// The extended member variable cannot store state because there is no field
var Int
    get() {
        return this.saveInt
    set(value) {
        this.saveInt = value

// Interfaces can define variables
interface Guy {
    var moneyLeft: Double
        get() {
            return 0.0
        set(value) {

Copy the code

Null type safety

class Book{}fun main(a) {
    val book=Book()
    if (book is Book){
        // Secure type conversion
        println((book as? Book)? .javaClass? .name) } }Copy the code

Kotlin- Built-in type

Basic types of

var b: String = "asdasd"
val c: Int = 15
Copy the code

String comparison,

= = = = =

== Compare whether the contents are equal

=== Compares whether the objects are equal

An array of

//it represents the index of the current array
var intArray = IntArray(3) { it +3}

// Get the length
// Print the array
// Print the array
val dd= arrayOf(1.2.3)
// Print by array index
val ss= intArrayOf(;
    for (i in ss.indices){

// Array traversal
for (d in dd){
// Write in function form
 dd.forEach { d->
// Omit d-> if default it is used
dd.forEach { println(it)}

/* Determine whether an array is in */
   if (5 in dd){
        println("Inside the array dd")}if (5 !in dd){
        println("Not in array DD")}Copy the code


// Creates a closed interval from 1 to 10
val intRange=1.10.
val charRange='a'.'z'
val longRange=1L.1000L

// Create an open interval
val intRangeExclusive=1 until  10 / / [1, 10)

// Reverse order interval
    val intRangeReverse=10 downTo  1 / / [10, 9,..., 1]

// Add step to interval
val intRange1=1.10. step 3 / /,4,7,9,10 [1]
 // Print the interval

Copy the code

Collections framework

// Immutable List, cannot be added or deleted
val intList: List<Int> = listOf(1.2.3)
/ / variable List
val intList2: MutableList<Int> = mutableListOf(

// Immutable map
val map:Map<String,Any> = mapOf("name" to "petterp"."ts" to 123)
val mutilMap:Map<String,Any> = mutableMapOf("name" to "petterp"."Ts" to 123)

// Create a List in Java
val intList = ArrayList<Int> ()val stringList = ArrayList<String>()

val intList = ArrayList<Int> ()// Write to List is equivalent to add
    for (i in 0.10.){
    // Remove an element. This is equivalent to remove
    // change an element to a value similar to set(0,101)
    intList[0] =101

val maps = HashMap<String, String>(10)
    // Add an element
    maps+=("key1" to "test")
    // Modify an element
    maps["key1"] ="petterp"

Copy the code

Any is equivalent to Object

If we look at the ArrayList in Kotlin, we see that

Where Typealias is equivalent to giving a new name to a type

We used “to” in the Map above

Var pair=””

 val map = HashMap<String, String>()

    val pair = "key" to "petterp"
    val pair2 = Pair("Hello"."Petterp")
    / / get keys
    val key = pair.first
    / / get the value
    val second = pair.second
    / / puts such as map
    map += pair
    map += pair2
    println("$key , $second")
Copy the code

What is deconstruction?

Used to resolve an object into variables

Use cases are as follows

fun main(a) {

    val map = HashMap<String, Int>()
    val kotlinBook = "Kotlin Core Technology" to 88
    val AndroidBook = Pair("Exploring Android Art".66)
    println("${kotlinBook.first} , ${kotlinBook.second}")
    map += kotlinBook
    map += AndroidBook

    println("Deconstruction begins \n\n")
    /* Deconstruct the declaration */
    / / reference
    // Break an object into variables
    println("Deconstruct objects")
    val (x, y) = Book("Kotlin Core Technology".88)

    println("\ n traverse map")
    // Using deconstruction to traverse the map is probably the best way
    for ((name, value) in map) {
        println("$name , $value")

    println("\n Ignore some deconstruction")
    // If you do not want to deconstruct some variables, pass the _ flag
    for ((name, _) in map)

    println("\n Using deconstruction in lambda")
    // Use destructuring to return a new map, with the key unchanged and only the value changed
    val maps = map.mapValues { (name, value) -> "5" }

    println("Using deconstruction in \n functions")
    Return two variables from the function
    val (name, money) = funcation()
    println("$name , $money")
    Return two variables from the function

data class Book(var name: String, var money: Int)

fun funcation(a): no1.Book {
    println("Went through a wave of operations.")
    return no1.Book("Exploring Android Art".99)}Copy the code
Kotlin Core Technology, 88 Deconstruction Start deconstructing objects Kotlin Core technology 88 Traversing Map Kotlin Core Technology, 88 Android Art Exploration, {Kotlin core technology =88, Android Art Exploration =66} {Kotlin core technology =5, Android Art Explorations =5} function using deconstruction has gone through a wave of manipulation in Android Art Explorations, 99Copy the code


In your judgment logic, act as an item that can never be called, for example if you have a when selection statement, you can use Nothing as your else return.

So what is Nothing

/** * Nothing has no instances. You can use Nothing to represent "a value that never exists": for example, * if a function has the return type of Nothing, it means that it never returns (always throws an exception). */
//* There is no instance. You can use Nothing to mean "a value that never exists" : for example, * if the return type of a function is Nothing, it means that the function never returns (always throws an exception).
public class Nothing private constructor(a)Copy the code

The following is an example:

The code looks like this:

fun test(type: String) =
    when (type) {
        "key1" -> Conditions of "1"
        "key2" -> "Conditions of 2"
        else -> caseDefault()

In other cases, the corresponding return type needs to be changed for the compiler's convenience. Otherwise, the corresponding exception needs to be manually added */ for each method
private fun caseDefault(a): String {
    throw RuntimeException("123")}Copy the code

Optimize this code using Nothing

fun test(type: String) =
        when (type) {
            "key1" -> Conditions of "1"
            "key2" -> "Conditions of 2"
            else -> doNothing()

private fun doNothing(message: String="Nothing is all"): Nothing {
    throw RuntimeException(message)
Copy the code

Kotlin function

:: Function reference

fun main(a) {
    // Function references several methods
    val x = Test::pp
    val x1: (Test, String) -> String = Test::pp
    val x2: (Test, String) -> String = x
    val x3: Function2<Test, String, String> = Test::pp

class Test {
    fun pp(name: String): String {
        return name
Copy the code

Function is used as an argument

fun main(a){
  val x1: (Test, String) -> String = Test::pp
println(Test().pp2(x1, 123))}class Test() {fun pp(name: String): String {
        return name
  fun pp2(name: (Test.String) - >String, value: Int): String {
        return "${name(Test(), "132")} , $value"}}Copy the code

The default parameters

fun main(a){
    // Default parameters
    // If your default argument is the first, you need to declare the display type
    default(name = "Android")}fun default(name: String, money: Int = 9){}Copy the code

Variable-length argument

fun main(a){
	 // Variable length parameter
    channels("Asd"."Asd")}fun channels(vararg args: String) {
Copy the code

Multiple return value parameters

fun main(a){
var (a, b, c) = test1()
    println("$a , $b ,$c")}fun test1(a): Triple<Int, String, String> {
    return Triple(123."asd"."asdfa");
Copy the code

Simple calculator

fun main(a) {
    val res: String = readLine()!!
    if (res.isEmpty()) {
        throw RuntimeException("Not null")}val operations = mapOf(
        "+" to ::plus,
        "-" to ::minus,
        "*" to ::times,
        "/" to ::div

    when {
        "+" in res -> {
            val (a, b) = res.split("+")
            println(operations["+"]? .invoke(a.toInt(), b.toInt())) }"-" in res -> {


        "*" in res -> {

        "/" in res -> {


fun plus(a: Int, b: Int): Int {
    return a + b

fun minus(a: Int, b: Int): Int {
    return a + b

fun times(a: Int, b: Int): Int {
    return a + b

fun div(a: Int, b: Int): Int {
    return a + b
Copy the code

Kotlin- type goes further

Class constructor

fun main(a) {
    Kang::money / / an error

Var or val equals a member variable, which is visible globally. Otherwise, it is visible only in the constructor (init block), similar to a local variable
class Kang(var name:String,money:Int)
Copy the code

Init block

The init will be synthesized into an init block at the end, which will be executed with the constructor

class Kang(var name:String,money:Int) {init {

    init {
    init {
        println("I am Petterp")}}Copy the code

Deputy constructor

In Java, a class can have multiple constructors, which means there are many ways to initialize the class, which means we have many living variables that cannot be used.

class Kang(override var name:String, money:Int):Test(name){
    init {

    init {

    init {
        println("I am Petterp")}fun void(a){}// The secondary constructor is invoked at the same time as the primary constructor
    constructor(name: String):this(name,123) {

Copy the code

If the primary constructor is not defined, then other secondary constructors can be called directly, not unlike Java. This is not recommended

class Test3{
    constructor(money:Int) :this("123") {}}Copy the code

Kotlin recommends writing in the form of the main constructor + default parameter. If you want to use it in Java, add @jvmoverloads

class Test3 constructor() {constructor(name:String){


    constructor(money:Int) :this("123") {}}Copy the code

Visibility of classes and members

Visibility type Java Kotlin
public public As with Java, the default is public
internal x Visible within the module
default Package visible, default x
protected Package and subclasses visible Class and subclass visible
private In the class Class or file

Internal tips

You can access internal directly in Java because Java doesn’t recognize internal in Kotlin. Below, in two modules



If we want to avoid Direct Java access to our code, we can add the following trick so that when Java calls it, it will report an error due to irregularities.

Set, get permissions for private properties

class Person(var age: Int.var name: String) {
     var fitstName: String = ""
        private set(value) {
            field = name
Copy the code

Visibility of top-level declarations

  • Top-level declarations refer to properties, functions, classes, etc., that are defined directly within the file

  • Protected is not supported in the top-level declaration

  • The top-level declaration is private to indicate that the file is internally visible

Delayed initialization

  • Class attributes must be initialized at construction time
  • Some members are initialized only after the class is constructed
  1. Latteinit lets the compiler ignore variable initialization and does not support basic types such as Int
  2. Developers must be able to fully determine the lifetime of variable values using Iateinit

There are three ways:

Lazy: recommended

 private val rvMainActivity by lazy {
Copy the code

Lateinit, use null

  private lateinit var recyclerView:RecyclerView
    override fun onCreate(savedInstanceState: Bundle?). {
Copy the code

? I don’t recommend it every time. Or!!!!!

  private varrecyclerView:RecyclerView? =null
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) recyclerView=findViewById( recyclerView? .adapter=RecyclerCustomAdapter(arrayListOf("123"."234"))}Copy the code

The agent


Used to monitor changes in property values, like an observer, and throw a change callback to the outside world when the property value is modified.

// Use the state variable to proxy the StateManager, so that the property changes to implement the monitoring
class StateManager{
    var state:Int by Delegates.observable(0){
        property, oldValue, newValue ->
        println("$oldValue->$newValue")}}fun main(a) {
    var stateManager = StateManager()
Copy the code

The property broker


fun main(a){
  // The property x delegates its accessor logic to the x object
    var x:Int by X() 

// Follow getValue,setValue, if val, only getValue is supported
class X{
    operator fun getValue(nothing: Nothing? , property:KProperty< * >): Int {
            return   2

    operator fun setValue(nothing: Nothing? , property:KProperty<*>, i: Int){}}Copy the code


Needs to be initialized before use

// Return a delegate with non-null arguments
 var name:String by Delegates.notNull()
Copy the code


It is used to notify the external changes when a property change has occurred, and to make some changes inside. It returns a state, true if the condition is met, false otherwise

 var vetoable: Int by Delegates.vetoable(0) { property, oldValue, newValue ->
        return@vetoable newValue == 123
Copy the code


Used to call the specified callback function when the property changes

   var observable:Int by Delegates.observable(0){
        property, oldValue, newValue -> 
Copy the code

Read and write Propertie using a property broker

class PropertiesDelegate(private val path: String, private val defaultValu: String = "") {
    private lateinit var url: URL

    private val properties: Properties by lazy {
        val prop = Properties()
        url = try {
            javaClass.getResourceAsStream(path).use {
        } catch (e: Exception) {
            try {
                ClassLoader.getSystemClassLoader().getResourceAsStream(path).use {
            } catch (e: Exception) {
                FileInputStream(path).use {

    operator fun getValue(thisRef: Any? , kProperty:KProperty< * >): String {
        return properties.getProperty(, defaultValu)

    operator fun setValue(thisRef: Any? , property:KProperty<*>, value: String) {
        properties.setProperty(, value)
        File(url.toURI()).outputStream().use {
  , "petterp")}}}abstract class AbsProperties(path: String) {
    protected val prop = PropertiesDelegate(path)

class Config : AbsProperties("") {
    var name by prop

fun main(a) {
    val config=Config()
Copy the code

The singleton Object

// Hungry Chinese singleton
object Singleton{

Copy the code
Java call @jVMstatic generate static method @jVMfield generate set,getCopy the code

Associated object

There are no static variables in Kotlin, so use companion objects instead of static variables. Note before use

class Test{

    companion object{
        fun of(a){}}}Copy the code

The inner class

class Outher{
    // Non-static inner class
    inner class Inner{}// Static inner class
    class staticInner{}}Copy the code

Internal Object

class Outher {
    // Non-static inner class
    inner class Inner {}// Static inner class
    class staticInner {
        object OutherObject {
            var x=5}}}fun main(a) {
Copy the code

Anonymous inner class

fun main(a) {
  	// Can inherit from a parent class or implement multiple interfaces
  	// Type - cross type ClassPath&Runnable (guess)
    object : ClassPath(), Runnable {
        override fun run(a){}override fun test(a){}}}abstract class ClassPath {
    abstract fun test(a)
Copy the code

Data classes


data class Book(val id:Int.val money:Double){
Copy the code

Difference from Javabeans

JavaBean data class
A constructor The default is no-parameter construction Property as a parameter
field Fields are private, getters/setters are public attribute
inheritance Can be inherited and can be inherited Uninheritable
Component There is no Equality, deconstruction, etc

How to use data Class properly

  • Use base types as property parameters

Enumeration class

enum class State{

enum class States(val id:Int){
    Idle(0),Busy(1)}// Enumeration implements the interface
enum class ClassPath : Runnable {

    override fun run(a){}}// Implement the interface method for each enumeration
enum class EnumOffer : Runnable {
    idle {
        override fun run(a) {
        override fun run(a){}}override fun run(a){}}Copy the code

Define extensions for the enumeration

fun State.sout(a) {
    println("Extension")}Copy the code

Enumeration comparison

enum class State {
    A, B

fun main(a) {
    val s = State.B
    if (s>State.A) println("ok")}Copy the code

Interval of enumeration

enum class State {
    A, B,C,D,E
fun main(a) {
    val s = State.B
    if (s inState.A.. State.C) println("ok")}Copy the code

Seal type

  • Sealed class is a special kind of abstract class
  • Subclasses of the sealed class are defined in the same file as themselves
  • There are a limited number of subclasses of the sealed class

In simple terms, the sealing class is equivalent to a specific subcategory of things, there is a clear type difference, subclass has a specific number. In the when expression, the sealing class is optimized

sealed class Book(val name: String)

class Android(name: String) : Book(name)
class Java(name: String, var money: Int) : Book(name)

fun main(a) {
    list(Java("Javaxx".99))}// If all conditions are met, no else is required
fun list(book: Book) = when (book) {
    is Android -> println(
    is Java -> println("${} --  ${}")}Copy the code

The difference between sealed classes and enumerated classes

Seal type Enumeration class
State implementation A subclass inherits Class to instantiate
State to count Subclasses to count Instance to count
Status differences Type differences Value differences

Inline class

  • An inline class is a wrapper around a type
  • An inline class is a type similar to a Java boxing type
  • The compiler optimizes with wrapped types whenever possible

Inline class usage scenarios

Unsigned type
inline class Unit constructor(internal val data: Int) : Comparable<Unit> {
    override fun compareTo(other: Unit): Int {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.}}Copy the code