On the Java platform numbers are physically stored as native types to the JVM, unless we need a nullable reference (such as Int?). Or generic. In the latter case, the numbers are boxed. Note that digital boxing does not necessarily preserve identity:

val a: Int = 10000
println(a === a) / / output "true"
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA === anotherBoxedA) / /!!!!!! Print "false"!!
Copy the code

On the other hand, it preserves equality:

val a: Int = 10000
println(a == a) / / output "true"
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA == anotherBoxedA) / / output "true"
Copy the code

Explicit conversion

Smaller types cannot be implicitly converted to larger types. This means that we cannot assign a Byte value to an Int variable without an explicit conversion.

val b: Byte = 1 // OK, literals are statically checked
val i: Int = b / / error
Copy the code

We can explicitly convert to broaden the number

val i: Int = b.toInt() // OK: explicitly widen
print(i)
Copy the code

Each numeric type supports the following conversions:

toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
Copy the code

The lack of implicit type conversions is rarely noticeable because types are inferred from context and arithmetic operations have overloads to convert properly, for example:

val l = 1L + 3 // Long + Int => Long
Copy the code

Characters are represented by the type Char. They can’t be treated as numbers

Kotlin also has special classes for representing arrays of native types with no boxing overhead: ByteArray, ShortArray, IntArray, and so on. These classes do not inherit from Array, but they share the same set of method attributes. They also have corresponding factory methods:

val x: IntArray = intArrayOf(1.2.3)
x[0] = x[1] + x[2]
Copy the code
// An integer array of size 5 and value [0, 0, 0, 0, 0]
val arr = IntArray(5)

// For example, initialize an array value with a constant
// An integer array of size 5 and values [42, 42, 42, 42, 42]
val arr = IntArray(5) { 42 }

// For example, use lambda expressions to initialize values in arrays
// An integer array of size 5 and value [0, 1, 2, 3, 4] (value initialized to its index)
var arr = IntArray(5) { it * 1 }
Copy the code

Import: If there is a name conflict in the imported item, you can use the as keyword to locally rename the conflicting item to disambiguate it:

import org.example.Message // Message is accessible
import org.test.Message as testMessage // testMessage stands for org.test.Message
Copy the code

Any expression in Kotlin can be labeled with a label. Tags are formatted as identifiers followed by @ signs, such as ABC @ and fooBar@ are valid tags (see syntax). To label an expression, we simply label it.

loop@for (i in 1.10.) {
     for (j in 1.10.) {
        if(j == 5) break@loop
        print(j)
    }
}

// Only 1234 is printed
Copy the code
listOf(1.2.3.4.5).forEach hehe@{
        if (it == 3) return@hehe 
        // Local returns to the caller of the lambda expression, namely the forEach loop
        // It is not possible to use break or continue
        print(it)
    }
Copy the code

If you want to break in a loop, you can simulate it by adding another layer of nested lambda expressions and returning from it nonlocally:

fun foo(a) {
    run loop@{
        listOf(1.2.3.4.5).forEach {
            if (it == 3) return@loop // Returns nonlocally from the lambda expression passed to run
            print(it)
        }
    }
    print(" done with nested loop")}Copy the code

When a return value is required, the parser preferentially selects the tag-bound return, i.e

return@a 1
Copy the code

Return a labeled expression (@a 1). (I don’t know what it’s for.)