This article is a brief summary of Kotlin’s content from Line 1, 3rd edition.

Variables and functions

variable

Because of Kotlin’s excellent type derivation mechanism, we can define variables using val and var

  • Val (short for value) is used to declare an immutable variable that cannot be reassigned once the tree is initially assigned, corresponding to a final variable in Java

     fun main() {
         val j = 10
         val s = "Hello World"
     }
    Copy the code
  • Var (short for variable) is used to declare a mutable variable that can be reassigned after the initial tree assignment, corresponding to non-final variables in Java

     fun main() {
         var j = 10
         j *= 10  
     }
    Copy the code

But Kotlin’s type inference mechanism doesn’t always work, so you need to explicitly declare variable types. The syntax is as follows:

 val a: Int = 10
Copy the code

In Kotlin, the basic data types in Java are completely abandoned and object data types are used entirely.

When defining variables, val is preferred. When val does not meet our requirements, var can be used instead.

function

Function definition, syntax rules as follows:

 fun methonMane(param1: Int, param2: Int): Int {
     return 0
 }
Copy the code

Defining functions can only be declared with fun

Parameter declaration format: Parameter name: parameter type

Function return value type declaration: () : Return value type, this part is optional, if the return value is needed, do not write

Simply define a function as follows:

 fun main() {
     val a = 37
     val b = 40
     val value = largerNumber(a, b)
     println("larger number is " + value)
 }
 ​
 fun largerNumber(num1: Int, num2: Int): Int{
     return max(num1, num2)
 }
Copy the code

Take a look at the syntactic sugar of the Kotlin function

When there is only one line of code in a function, Kotlin allows us to write a single line of code at the end of the function without having to write the function body.

Simplify the largerNumber function above:

 fun largerNumber(num1: Int, num2: Int): Int = max(num1, num2)
Copy the code

The return value type can be omitted for reasons of deduction, so let’s simplify further:

 fun largerNumber(num1: Int, num2: Int) = max(num1, num2)
Copy the code

Logical control of a program

There are three main types of execution statements: sequential statements, conditional statements and circular statements.

Conditional statements

If conditional statement

Conditional statements in Kotlin are implemented in two main ways: if and when

Let’s start with a simple example:

 fun largerNumber(num1: Int, num2: Int): Int{
     var value = 0
     if (num1 > num2) {
         value = num1
     } else {
         value = num2
     }
     return value
 }
Copy the code

As you can see here, the usage is exactly the same as in Java, but the if statement in Kotlin has the additional capability of having a return value

The return value is the return value of the last line of code in each condition of the if statement. Let’s simplify this:

fun largerNumber(num1: Int, num2: Int): Int {
    return if (num1 > num2) {
        num1
    } else {
        num2
    }
}
Copy the code

Take a closer look at the current code and continue to simplify the code as described above:

fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) num1 else num2
Copy the code

When conditional statement

Write a simple example to see how when can be used to query test scores, enter a student’s name, and return that student’s test scores.

Let’s start with an if statement

fun getScore(name: String) = if (name == "Tom") {
    86
} else if (name == "Jim") {
    77
} else if (name == "Jack") {
    95
} else if (name == "Lily") {
    100
} else {
    0
}
Copy the code

If and else if, curly braces, and name are all repeated.

fun getScore(name: String) = when (name) {
    "Tom" -> 86
    "Jim" -> 77
    "Jack" -> 95
    "Lily" -> 100
    else -> 0
}
Copy the code

As you can see, the code is much cleaner, and the WHEN statement can also have a return value or use single-line syntactic sugar

The WHEN statement allows you to pass in an argument of any type, and then you can define a list of conditions in the structure of when in the following format:

Matching values -> {execute logic}

In addition to exact matching, the WHEN syntax also allows type matching.

fun checkNumber(num: Number) {
    when (num) {
        is Int -> println("number is Int")
        is Double -> println("number is Double")
        else -> println("number not support")
    }
}
Copy the code

In the code above, the is keyword is at the heart of type matching, which is equivalent to the Instanceof keyword in Java.

The when statement can also be used without arguments. Let’s see how it is used.

fun getScore(name: String) = when {
    name == "Tom" -> 86
    name == "Jim" -> 77
    name == "Jack" -> 95
    name == "Lily" -> 100
    else -> 0
}
Copy the code

As you can see, this way of writing the expression of the judgment completely inside the structure of when. Now this is not as good as the above, but there are some special cases where this is necessary. For example, if everyone whose name begins with Tom has a score of 86, this scenario would not be possible with the when statement with no parameters.

fun getScore(name: String) = when {
    name.startWith("Tom") -> 86
    name == "Jim" -> 77
    name == "Jack" -> 95
    name == "Lily" -> 100
    else -> 0
}
Copy the code

Ok, so that’s the use of ‘when’

Looping statements

There are two main types of loop statements in Java: while and for. Kotlin also provides while and for loops, where the while loop is exactly the same in use as In Java without much explanation. I’m going to focus on the for loop.

Kotline has made major changes to the for-loop. The most commonly used for-i loop in Java is discarded in Kotlin, while the other for-each loop in Java has been greatly enhanced by Kotlin to become for-in.

Kotlin added the concept of an interval, which can be represented by the following code:

val range = 0.. 10Copy the code

The appeal code represents [0, 10], a closed interval containing 0 and 10

fun main() { for (i in 0.. 10) { println(i) } }Copy the code

In many cases, a double-ended closed interval is not as good as a single-ended closed interval. Suppose you create a single-ended closed interval from 0 to 10, you can use the until keyword to create it

val range = 0 until 10
Copy the code

If you want to skip elements in a for-in loop, use the step keyword

Fun main() {for (I in 0 until 10 step 2) {0 2 4 6 8 println(I)}Copy the code

It can be known that… The left end of the interval must be less than or equal to the right end of the interval. These two keywords create an ascending interval.

If you want to create a descending range, you can use the downTo keyword as follows:

fun main() {
    for (i in 10 downTo 1) {
        println(i)
    }
}
Copy the code

A descending interval of [10,1] is created, and some elements of the descending interval can also be skipped using the step keyword.

object-oriented

class

Object oriented: Personally, class is a kind of encapsulation of things, or a general name of a certain kind of things, such as people, cars, houses and other things, can be encapsulated into a class, the class name is usually a noun. Classes have their own fields and functions, fields representing properties owned by the class, and functions representing some behavior used by the class.

Kotlin also uses the class keyword to declare a class

class Person {
    var name = ""
    var age = 0
    
    fun eat() {
        println(name + " is eating. He is " + age + "years old.")
    }
}
Copy the code

So let’s instantiate this

val p = Person()
Copy the code

Kotlin instantiates a class in much the same way as Java, minus the new keyword. Because when you call the constructor of a class, your intent is simply to instantiate the class, even without new, it makes your intent clear.

fun main() {
    val p = Person()
    p.name = "Jack"
    p.age = 19
    p.eat()
}
Copy the code

Inheritance and constructors

The concept and Java inside the basic same, is not quite the same usage.

In Java, any class that does not have a final definition can be inherited, but in Kotlin this is different. By default, all non-abstract classes are prohibited from being inherited.

To allow the Person class to be inherited, simply prefix the Person class with the open keyword, as shown below:

open class Person {
    ...
}
Copy the code

With the open keyword, the Person class is designed specifically for inheritance, so that Person can be inherited.

We create a class that extends from Person, which in Java is extends, but in Kotlin becomes a colon, as follows:

class Student : Person() {
    ...
}
Copy the code

It’s important to understand why you put parentheses after Person, because you’re designing for primary and secondary constructors.

Principal constructor

Let’s learn about primary and secondary constructors.

The primary constructor is our most common constructor. Each class has a primary constructor that takes no arguments by default, and it can also be explicitly specified. The primary constructor does not have a function carrier, so it can be defined directly after the class name.

class Student(val sno: String, val grade: Int) : Person() {
}
Copy the code

Instantiation of the Student class requires passing in the two parameters required by the constructor as follows:

val student = Student("a123", 5)
Copy the code

Kotlin provides an init structure in which all the main constructor logic can be written:

class Student(val sno: String, val grade: Int) : Person() {
    init {
        println("sno is " + sno)
        println("grade is " + grade)
    }
}
Copy the code

Now if we were to create an instance of the Student class, we would print out the values passed in the constructor.

So far, it’s easy to understand why parentheses are required when inheriting from a parent class. Because of a Java inheritance feature, constructors in a child class must call constructors in the parent class. This rule is also observed in Kotlin.

Now looking back at the Student class, we declare the primary constructor. Depending on the nature of inheritance, the constructor of a child class must call the constructor of its parent class. However, many times our primary constructor does not have a carrier. At this point a lot of people might think of calling the parent constructor in an init structure, which might be one way to do it, but there are a lot of scenarios where you don’t need to write an init structure. Instead of using this design, Kotlin uses parentheses at inheritance time to specify which constructor in the parent class is called by the primary constructor of a subclass.

class Student(val sno: String, val grade: Int) : Person() {
}
Copy the code

Now that you look at the code, you can see why the parentheses were added. This means that the primary constructor of the Student class calls the no-argument constructor of Person when initialized. The parentheses cannot be omitted even if there are no arguments.

If we modify the Person class to place the name and age in the main constructor, as follows:

open class Person(val name: String, val age: Int) {
    ...
}
Copy the code

The Student class defined before this error is reported, and we need to modify the Student class:

class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
}
Copy the code

Note that when we add name and age fields to the main constructor of the Student class, we cannot declare them as val, because parameters declared as val or var in the main constructor will automatically become fields of the class, causing conflicts with the name and age fields of the parent class. Therefore, the name and age parameters are scoped only in the main constructor without any keywords.

You can now create an instance of the Student class with the following code:

val student = Student("A123", 5, "Jack", 19)
Copy the code

So that’s it for the main constructors, so let’s look at the constructors

subconstructor

Briefly, any class can have only one primary constructor, but can have multiple secondary constructors. Subconstructors can also be used to instantiate a class. subconstructors have function bodies.

Kotlin states that when a class has both primary and secondary constructors, all secondary constructors must call the primary constructor (including indirect calls)

Here’s a simple example:

class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
    constructor(name: String, age: Int) : this("", 0, name, age) {
    }
   
    constructor() : this("", 0) {
    }
}
Copy the code

The secondary constructor is defined by using the Construtor keyword, which defines two secondary constructors

The first secondary constructor takes the name and age arguments, and then it calls the primary constructor with the this keyword and assigns the sno and grade arguments to their initial values.

The second subconstructor takes no arguments, then calls the first subconstructor with this keyword and assigns the name and age arguments to their initial values, so the second subconstructor also calls the main constructor indirectly, so this is still valid.

How do I initialize the Student class

val student1 = Student()
val student2 = Student("Jack", 19)
val student3 = Student("a123", 5, "Jack", 19)
Copy the code

This is a common scenario for subconstructors, but there is a special case for subconstructors: there is only a subconstructor in a class, but no primary constructor. This is really rare, but allowed in Kotlin.

A class does not have a primary constructor when it does not explicitly define a primary constructor and defines a secondary constructor.

class Student : Person {
    constructor(name: String, age: Int) : super(name, age) {
    }
}
Copy the code

Note the code changes here. The Student class does not explicitly define the primary constructor, and because the secondary constructor is defined, the Student class now has no primary constructor. Since there is no main constructor, there is no need for parentheses when inheriting from the Person class.

In addition, since the Student class has no primary constructor, the secondary constructor can only call the parent constructor directly. This code also changes this to the super keyword.

interface

The content of the interface is basically the same as Java.

To be continued