kotlin basic grammar

1, Basic data type

Several are introduced.

  • value type
  • Character type
  • Boolean

1.1 value type

The basic numeric types of Kotlin include Byte, Short, Int, Float, Long and Double

data typeBit length
Byte8
Short16
Int32
Float32
Long64
Double64

It is described in the following situations:

  • Use of value type;
  • Conversion of numeric type to binary, octal and hexadecimal;
  • Numerical comparison;
  • Value type conversion;
  • Numeric type bit operation;

1.1.1 value type usage

Basic numeric types (Byte, Short, Int, Float, Long, Double) are used.

Numerical method:

// Int: numeric type variable definition
// Var < identifier >: < type > = < initialization value >
val aa: Int = 123
val aa = 123

// Float: use f or F suffix
val aa = 123.5f
val bb = 123.5F

// Long: ends with a capital L
val aa = 1234_5678_9012_3456L

// Double default
val aa = 123.5

1.1.2 binary, octal and hexadecimal

Basic value type, binary, octal and hexadecimal support.

// Decimal: 123
val aa = 123

// Binary: beginning with 0b
val aa = 0b00001011

// Octal: temporarily not supported

// Hex: beginning with 0x
val aa = 0x0F

1.1.3 numerical comparison

There are no basic data types in Kotlin, only encapsulated digital types.
For each variable we define, Kotlin actually encapsulates an object for you, which can ensure that there will be no null pointer. Therefore, when comparing two numbers, there is a difference between comparing the data size and whether the two objects are the same.

In Kotlin:

  • Three equal signs = = = indicate the address of the comparison object;
  • Two = = means comparing the size of two values.
// Address space comparison (same object)
val a: Int = 10000
println(a === a) // true

// Address space comparison (different objects)
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA === anotherBoxedA) //  false object address is different

// Size comparison
println(boxedA == anotherBoxedA) // true, equal values

1.1.4 type conversion

Due to different representations, the smaller type is not a subtype of the larger type.
Therefore, smaller types cannot be implicitly converted to larger types. Therefore, if Byte is converted to Int, display conversion is required.

val b: Byte = 1  
// Display conversion
val i: Int = b.toInt() 

Each data type has the following methods, which can be converted to other types:

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

1.1.5 bit operation

// Left shift
shl(bits)
// Right shift
shr(bits) 
// Unsigned right shift
ushr(bits) 

// And
and(bits)
// or
or(bits)
// XOR
xor(bits)
// reverse
inv() 

1.2 character type

Char must be enclosed in single quotation marks'. For example, ordinary characters' 0 'and' a '.

// Address space comparison (same object)
val a: Char = '9'
// Display conversion
val i: Int = a.toInt() 

1.3 string

String variable declaration:

// Single line string
val str = "123"
// Multiline string
val text = """
    Multiline string
    Multiline string
    """ 

String usage:

// Take the characters in the string
val str = "123"
println(str[2])  
// Take the characters in the string
for (c in str) {
    println(c)
}

// Display character conversion
val i: Int = str.toInt{) 

// Go space 
val text = """
    Multiline string
    Multiline string
    """.trimMargin()
	

String template:

// $represents a variable name or value
// $varName represents the value of the variable
// ${varName.fun()} represents the method return value of the variable

fun main(args: Array<String>) {
	var a = 1
	// Simple name in template:
	val s1 = "a is $a" 

	// Any expression in the template:
	val s2 = "${s1.replace("is", "was")}, now is $a"
	
    print(s2)
}

Boolean 1.3

Boolean is represented by Boolean type, which has two values: true and false.

val b: Boolean = true

2, Variable

  • Variable definition
  • Variable NULL check
  • Variable type detection is
  • Variable interval representation
  • Variable length parameter vararg

2.1 variable definition

  • var variable;
  • val read-only variable, which is equivalent to the final variable in java. val variable must be initialized when it is created.
var <Variable identifier> : <Variable type> = <Variable initialization value>

// Variable initialization:
var a: Int = 1
// Read only variable initialization:
val b: Int = 2

2.2 variable NULL check

  • Type followed by? Indicates that it can be empty
    var aa: String? = "23"
  • Add after identifier!! Indicates that if it is null, an exception is thrown normally;
    val aa = age!!.toInt()
  • Add after Identifier? Indicates that if it is empty, it returns null
    val aa = age?.toInt()
  • ?: Use: Return - 1 if age is null
    val ages2 = age?.toInt() ?: -1

2.3 variable type detection

// Type detection
if (obj is String) {
	// After type judgment, obj will be automatically converted to String type by the system
	return obj.length 
}

2.4 variable interval

  • Use... To represent rangeTo (from small to large)
    for (i in 1..4) print(i) / / output "1234"
  • Use downTo (from large to small)
    for (i in 4 downTo 1 step 2) print(i) / / output "42"
  • Use step to specify the step size
    for (i in 1..4 step 2) print(i) / / output "13"
  • Use until to exclude end elements
// i in [1, 10) excludes 10
for (i in 1 until 10) {   
     println(i)
}

2.5 variable length parameters

Variable side length parameter vararg

fun vars(vararg v:Int){
    for(vt in v){
        print(vt)
    }
}

// test
fun main(args: Array<String>) {
    vars(1,2,3,4,5)  // Output 12345
}

3, Method

  • Method definition
  • lambda anonymous method

3.1 method definition

Keyword used in method definition: fun,
Parameter format: parameter type

// Method definition with return value
fun sum(a: Int, b: Int): Int {
	// Int parameter, return value int 
	return a + b 
}
// No return value method definition
fun printSum(a: Int, b: Int) {
	print(a + b) 
}

3.2 lambda anonymous method

// test
fun main(args: Array<String>) {
    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
    println(sumLambda(1,2))  // Output 3
}

4, Condition control

  • if expression
  • when expression

4.1 if expression

An if statement contains a Boolean expression and one or more statements.

// Use if else 
var max: Int
if (a > b) {
    max = a
} else {
    max = b
}

// Use if expressions
var max = a 
if (a < b) max = b
 
// Use as an expression: assign the result of the expression to a variable
val max = if (a > b) a else b
// Use as an expression: assign the result of the expression to a variable
val max = if (a > b) {
    a
} else {
    b
}

4.2 when expression

when compares its parameters with all branch conditions in order until a branch satisfies the condition.
when is similar to the switch operator in other languages.
The when expression else is the same as the default of switch. If other branches do not meet the conditions, the else branch will be evaluated.

//
when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // Pay attention to this block
        print("x Not 1, not 2")
    }
}
// 
when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

when expression, use in to detect whether a value is in or not in an interval or set:

//
when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

when expression, use is to detect whether a value is or is not a specific type of value:

//
when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}

5, Cycle control

  • for loop
  • While and do while
  • return, break and continue

5.1 for loop

The for loop can traverse any object that provides an iterator.

//
for (item in collection) print(item)
// The loop body can also be a statement
val items = listOf("apple", "banana", "kiwi")
for (item in items) println(item)
// The loop body can also be a block of code
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
    println(item)
}

// Traversing an array or a list by index
for (i in array.indices) {
    print(array[i])
}

// Using the withIndex library method
for ((index, value) in array.withIndex()) {
    println("the element at $index is $value")
}

5.2 while and do while

The functions of while and do while are similar; The difference is that do while is executed at least once.

fun main(args: Array<String>) {
    // while loop
    var x = 5
    while (x > 0) {
        println( x--)
    }
	
    // do... while loop
    var y = -1
    do {
        println(y--)
    } while(y>0)
}

// results of enforcement
// while loop
5
4
3
2
1
// do... while loop
-1

5.3 return, break and continue

  • return returns from the method that most directly surrounds it or the anonymous method;
  • break terminates the loop that most directly surrounds it;
  • continue continues the next cycle that most directly surrounds it;

Examples of usage are as follows:

fun main(args: Array<String>) {
    for (i in 1..10) {
        if (i==3) continue  // When i is 3, skip the current cycle and continue the next cycle
        println(i)
        if (i>5) break   // Jump out of loop when i is 6
    }
}

Tags in Kotlin
In Kotlin, any expression can be marked with a label.
The format of label is identifier followed by @ symbol. For example, abc @ and fooBar @ are valid labels.

// Limit break with label
loop@ for (i in 1..100) {
    for (j in 1..100) {
        if (......) break@loop
    }
}

6, Class

  • Class definition
  • abstract class
  • Nested class
  • Inner class
  • Anonymous Inner Class

6.1 class definition

  • Class keyword
    Class is declared with the keyword class, followed by the class name:
    class Person{}
  • Main construction method
    A class can have a primary constructor and multiple secondary constructors.
    The main constructor is part of the class header, after the class name. The main constructor cannot contain any code. The initialization code can be placed in the initialization code segment init.
  • Secondary construction method
    If the class has a primary constructor, each secondary constructor must directly or indirectly proxy the primary constructor through another secondary constructor; Use this keyword to proxy another constructor in the same class;
  • Class attribute declaration
    Non empty attributes in the class must be initialized at the time of definition, but they can also be delayed through the lateinit keyword.
    In addition, Kotlin provides a back-end variable field mechanism, but the field keyword can only be applied to the accessor of the attribute.

Examples of Kotlin class construction codes are as follows:

// Class keyword: the class uses the keyword class declaration, followed by the class name;
// Construction method: class with construction method (constructor keyword can be omitted);
class Person constructor (name: String){

    // Class attribute: non empty attribute must be initialized at the time of definition;
    // Class attribute: Kotlin provides a back-end variable field mechanism, but the field keyword can only be applied to the accessor of the attribute;
    var mName: String = "xia"
        get() = field.toUpperCase()   // Convert variable to uppercase after assignment

    var mAge: Int = 16
        set(value) {
            if (value < 20) {       // If the value passed in is less than 20, this value is returned
                field = value
            } else {
                field = 18         // Otherwise, return to 18
            }
        }
    
    // Construction method: the main constructor cannot contain any code, and the initialization code can be placed in the init code segment;
    init {
        this.mName = name
        println("init name $mName")
        println("init age $mAge")
    }
    // Secondary construction method: if the class has a primary construction method, each secondary construction method must directly or indirectly proxy the primary construction method through another secondary construction method;
    // Secondary constructor: use this keyword on behalf of another constructor in the same class;
    constructor (name: String, age:Int) : this(name) {
        // Secondary construction method
        this.mName = name
        this.mAge = age
        println("constructor init name $mName")
        println("constructor init age $mAge")
    }

}

// main program entry
fun main(args: Array<String>) {
	// create object
    var person: Person = Person("xiaxl")

    // full name
    person.mName = "xiaxueliang"
    println("changeName:${person.mName}")

    // Age
    person.mAge = 21
    println("changeAge:${person.mAge}")

}

6.2 abstract classes

Abstract class itself and some members in the class can be declared as abstract type.

// Abstract class itself and some members in the class can be declared as abstract type
abstract class Person {
    abstract fun changeName()
}

6.3 nested classes

You can nest classes in other classes.

// Nested classes: you can nest classes in other classes
// External class
class Outer {                  
    private val outerProperty: Int = 1

    // Nested class
    class Person {             
        fun changeAge() = 18
    }
}

fun main(args: Array<String>) {
	// Nested classes: calling external classes Nested classes Nested class methods / properties
    val age = Outer.Person().changeAge() 
    
    println(age)    // Output 18
}

6.4 internal class

The inner class is represented by the inner keyword.
The inner class will have a reference to the object of the outer class, so you can access the member properties and methods of the outer class. Can use this@label Tag to access this from an external scope.

// Inner class: the inner class is represented by the inner keyword.
// Internal class: the internal class will have a reference to the object of the external class, so you can access the member properties and methods of the external class.
class Outer {
    private val iProperty: Int = 18
    var sProperty = "outerName"

    // Inner class
    inner class Person {
        // Accessing external class members
        fun test01() = iProperty  

        // Get the external class object and access the external class members
        fun test02() {
            // Internal classes: Using` this@label `Tag, access from external scope ` this`
            var outerObj = this@Outer 
            // Accessing external class members
            println("inner sProperty: " + outerObj.sProperty)
        }
    }
}

fun main(args: Array<String>) {

    val iProperty = Outer().Person().test01()
    println("main Person test01: " + iProperty)
    //
    val sProperty = Outer().Person().test02()   
    println("main Person test02: " + sProperty)
}

6.5 anonymous inner class

// Define interface
interface PersionInterFace {
    fun changeName()
}

// Define class
class Persion {
    var v = "Member properties"
    
    // Definition method
    fun setInterFace(testObj: PersionInterFace) {
        testObj.changeName()
    }
}


// Program entry
fun main(args: Array<String>) {

    // Gets the object of the class
    var persion = Persion()

    // An object expression is used to create an interface object, that is, an instance of an anonymous inner class.
    persion.setInterFace(object : PersionInterFace {
        override fun changeName() {
            println("Implementation of anonymous inner classes changeName method")
        }
    })
}

7, Inherit

All classes in Kotlin inherit the Any class, which is a superclass of all classes.
In addition, Any class provides three methods by default: equals(), hashCode(), toString().

  • Construction method
  • override method
  • Overridden properties

7.1 construction method

  • If the subclass has a main constructor:
    The base class must be initialized in the subclass main constructor.
// If the subclass has a main constructor: the base class must be initialized in the main constructor of the subclass.
// Base class
// If a class is to be inherited, it can be decorated with the open keyword
// Any class is a superclass of all classes
open class Person(var name:String, var age:Int){

}
// Subclass Student
class Student(name:String, age:Int, ,number:String) : Person(name, age) {

}

// test
fun main(args: Array<String>) {
    var s =  Student("xia", 18, "n987456123")
    println("full name: ${name}")
    println("Age: ${age}")
    println("Student number: ${number}")
}
  • If the subclass does not have a primary constructor:
    You must initialize the base class with the super keyword in each secondary constructor of the subclass.
// If the subclass does not have a primary constructor: the base class must be initialized with the super keyword in each secondary constructor of the subclass.
// Base class
open class Person(name:String){
    // Construction method of base class
    constructor(name:String,age:Int):this(name){
        println("--- Construction method of base class ---")
        println("full name: ${name}")
        println("Age: ${age}")
    }
}

// Subclass Student
class Student:Person{

    // Subclass sub construction method
    constructor(name:String,age:Int,number:String):super(name,age){
        println("--- Subclass secondary construction method ---")
        println("full name: ${name}")
        println("Age: ${age}")
        println("Student number: ${number}")
    }
}

fun main(args: Array<String>) {
    var s =  Student("xia", 18, "number987456123")
}

7.2 rewriting method

In the base class, when declaring a function method, this method defaults to final and cannot be overridden by subclasses.
If subclasses are allowed to override this method, you need to manually add an open modifier, and subclass override methods need to use the override keyword.

// Base class
// Method override: in the base class, when using fun to declare a function method, this function method defaults to final and cannot be overridden by subclasses.
// Method Rewriting: if subclasses are allowed to rewrite this method, you need to manually add an open modifier, and subclass rewriting methods need to use the override keyword.
open class Person{
	// Allow subclass overrides
    open fun study(){       
        println("Learning makes me happy")
    }
}

// Subclass
class Student : Person() {
	// rewrite
    override fun study(){    
        println("I am a student.")
    }
}

// Program entry
fun main(args: Array<String>) {
    val s =  Student()
    s.study();

}

7.3 override attributes

Use the override keyword, or you can use the override keyword in the main constructor as part of the property declaration.

interface Persion {
    val age: Int
}

// Override attribute: use override keyword
class Student1 : Persion {
    override var age: Int = 9
}
// Override attribute: use the override keyword in the main constructor as part of the attribute declaration
class Student2(override val age: Int) : Persion{

}

// Program entry
fun main(args: Array<String>) {
    var s1 =  Student1()
    println("Student1: "+s1.age);
    
    var s2 =  Student2(18)
    println("Student2: "+s2.age);
}

8, Interface

Kotlin uses the interface keyword to define an interface.

  • Methods in the interface are allowed to have default implementation;
  • Attributes in an interface can only be abstract and cannot be initialized;
  • A class can implement one or more interfaces. When implementing multiple interfaces, you may encounter the problem that the same method inherits multiple implementations.
// Interface class A
interface AInterface {
	// Interface: attributes can only be abstract and cannot be initialized
	var name:String 

	// Interface: method can have default implementation
	// Unimplemented method
    fun changeName()   
    // Implemented methods 
    fun changeAge() {  
    	println("AInterface changeAge")
    }
}

// Interface class B
interface BInterface {
	// Interface: method can have default implementation
	// Unimplemented method
    fun changeName() {  
        println("BInterface changeName")
    }  
    // Implemented methods 
    fun changeAge() {  
        println("BInterface changeAge")
    }
}
 
class C : AInterface {
	// Overridden properties 
	override var name: String = "xiaxl" 
    // override method 
    override fun changeName() { 
        println("Class C changeName")
    }   
}
 
class D : AInterface, BInterface {
	// Overridden properties 
	override var name: String = "xiaxl" 
    // override method 
    override fun changeName() {
        // super<AInterface>.changeName()
        super<BInterface>.changeName()

        println("Class D changeName")
    }
    // override method 
    override fun changeAge() {
        super<BInterface>.changeAge()

        println("Class D changeAge")
    }
}
 
fun main(args: Array<String>) {
    val d =  D()
    println(" ")
    d.changeName();
    println(" ")
    d.changeAge();
}

9, Enumeration

enum class Color(val rgbValue: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}

fun main(args: Array<String>) {
    // 
    var color:Color=Color.GREEN
    
    // Print enumeration name
    println(color.name)
    // Print enumeration order
    println(color.ordinal)
    // Print enumerated values
    println(color.rgbValue)

}

10, Data type

First, why use data classes:
The advantage of Kotlin replacing ordinary classes with data classes is that Kotlin will help us generate a lot of code and save a lot of repetitive work.

  • To use a data class in Kotlin, you only need to add the data keyword before the class keyword. The compiler will automatically deduce the related functions equals(), toString(), copy(), componentN(), hashCode(), from the main constructor according to the declared attributes;
  • In Kotlin, the data class automatically declares the attribute field with the same name as the constructor input parameter, and automatically implements the accessor method set/get of each attribute field;

Declare data class:

// Declare data type
data class <Class name> <Primary constructor parameters> <:Inheritance classes and implementation interfaces> { /*Class body*/ }

Examples of data types:

// Create data class
data class Person(var name :String, var age :Int){
	// In vivo life attribute
	var job: String = "student"
}

// Program entry
fun main(args: Array<String>) {
    var p = Person("xiaxl",18)

	// Call getter of data class
    println(p.name) 
    println(p.age) 
    println(p.job) 

    // Call the setter of the data class
    p.name = "xiaxueliang" 

    // Automatically call toString() method
    println(p) 

    //Call the hashCode() method to output the memory address
    println(p.hashCode())  

    // Resolve constructor componentN
    val (name, age) = p
    println("name = $name, age=$age")
}

11, Generics

// Generic example
class Persion<T>(t : T) {
    var value = t
}

// Generic example
fun <T> doPrintln(t: T) {
    when (t) {
        is Int -> println("Integer number: $t")
        is String -> println("string uppercase : ${t.toUpperCase()}")
        else -> println(" Not an integer, not a string")
    }
}


// Program entry
fun main(args: Array<String>) {
    var pInt = Persion<Int>(18)
    var pString = Persion<String>("xiaxl")

    // output
    doPrintln(pInt.value)
    doPrintln(pString.value)
}

12, Associated object

  • Companion Object
  • Object declaration

12.1 associated objects

Associated objects exist with the existence of classes.
In kotlin, classes do not have static methods. In most cases, kotlin recommends using package level functions as static methods. Kotlin will treat package level functions as static methods.

// Companion Object 
class MyConstant {
    companion object {
        var num: Int = 100
 
        fun doPrint() {
            println("method test")
        }
    }
}

// Program entry
fun main(args: Array<String>) {

    // variable
	var num = MyConstant.num
    println("num: $num")
    // method
    MyConstant.doPrint()
}

12.2 object declaration

Kotlin can obtain a singleton through object declaration. Kotlin uses the object keyword to declare an object.

// Object declaration
object Singleton{
    // attribute
    val name = "xia"
    // method
    fun doPrint(age: Int){
        println("$name ---- $age")
    }
}

// Program entry
fun main(args: Array<String>) {
    // Single case
    Singleton.doPrint(18)
}

Keywords: kotlin

Added by future448 on Wed, 02 Mar 2022 12:47:06 +0200