Chapter 2 Introduction to Kotlin
-
The working principle of
Programming languages fall into two broad categories: compiled and interpreted. Java is an interpreted language. Java code is compiled to generate class files that are recognized only by the Java virtual machine. The Java virtual machine acts as an interpreter, interpreting the mutated class file as binary data that the computer can recognize before executing the program.
Kotlin’s compiler compiles Kotlin code into class files. The Java virtual machine doesn’t care if a class file is compiled from Java or Kotlin, it recognizes a class file as long as it meets the specification. That’s how Kotlin works.
-
Variables and functions
-
variable
Only two keywords are allowed to be declared before a variable: val and var
Val (short for value) declares an immutable variable, always using val in preference to declaring the variable
Var (variable short) declares a mutable variable
val a: Int = 10 Copy the code
Kotlin completely ditches the basic data types in Java and uses all object data types.
Shift + CTRL + P displays variable types
-
Basic types of
Kotlin unwrapped type (Byte, Integer…)
Byte, int, Float&Long, Char, String
// val c = 12345678910l // compile error. // L should be capitalized val c = 12345678910L // ok Copy the code
val e: Int = 10 //val f: Long = e // implicitness not allowed // Explicit conversion, implicit conversion does not compile val f: Long = e.toLong() // implicitness not allowed Copy the code
val k = "Today is a sunny day." val m = String("Today is a sunny day.".toCharArray()) // Compare addresses println(k === m) // compare references. // If the value is equal, Java compares the address. Java compares the content using equals println(k == m) // compare values. Copy the code
-
Unsigned type
UByte, integer (UShort&UInt&ULong)
val g: UInt = 10u val h: ULong = 100000000000000000u Copy the code
-
String template
val slogan = "To be No.1" println("Value of String 'j' is: $slogan") // no need brackets println("Length of String 'j' is: ${slogan.length}") // need brackets Copy the code
val sample = "" "
Hello World Hello World
This is a demo page.
-
-
An array of
IntArray: IntArray, Int boxing Array: Array
Integer is a wrapper type for int, which is more wasteful than int. As a good coder, you’ll want to use int instead of Integer if the scope allows.
So let’s look at two approaches
fun myList(vararg inner: Int) { println(inner.size) } fun myList2(vararg inner2: Int?). { println(inner2.size) } Copy the code
The only difference between these two methods is do you have an Int after it? Number. Let’s look at the important parts of the decompiled code first
Tools->Kotlin->Show Kotlin Bytecode->Decompile
public static final void myList(@NotNull int... inner) { Intrinsics.checkNotNullParameter(inner."inner"); int var1 = inner.length; boolean var2 = false; System.out.println(var1); } public static final void myList2(@NotNull Integer... inner2) { Intrinsics.checkNotNullParameter(inner2, "inner2"); int var1 = inner2.length; boolean var2 = false; System.out.println(var1); } Copy the code
Look carefully at the signature of the parameter
- MyList is int… inner
- MyList2 is an Integer… inner2
You can wonder why the Kotlin compiler compiles this way. Right? In fact, the root cause is? , can be empty. When the Kotlin compiler decides that a parameter cannot be null, it is perfectly possible to use unwrapped types to accept parameters, making more efficient use of resources.
val intArrayOf = intArrayOf(1.3.4) myList(*intArrayOf) myList(1.2.3) // Notice the null here val array = arrayOf(1.3.4.null) myList2(*array) myList2(1.2.3) Copy the code
The above code needs to be noted:
- statement
Int
An array of type,Kotlin
Two methods are provided, one isintArrayOf()
, one isarrayOf()
; intArrayOf
Stress isint
, similar toJava
In theint[]
, so the parameter cannot benull
arrayOf
similarJava
In theInteger[]
, so you can assign to itnull
- Arrays in Kotlin cannot be assigned directly to morphable parameters
vararg
, you need to pass the keyword*
- Reflect on that when we create
array
If you don’t need tonull
Are you usingintArray
Better?
val array = arrayOf(1.3.4.null) // Prints the contents of the array println(array.contentToString()) // Get the length println(array.size) // reassign array[1] = 4 / / value println(array[0]) / / traverse for (i in array) { } // Check if the value is in the array if (1 in array) { println("1 exists in variable 'array'")}Copy the code
-
interval
// [0,10] discrete values val intRange: IntRange = 1.10. / / [0, 10) val intRange1: IntRange = 1 until 10 / / [10, 9,..., 1] val intProgression = 10 downTo 1 / / step length val intProgression1 = 1.10. step 2 for (i in intProgression1) { // 1 3 5 7 9 print("$i ")}// 1, 3, 5, 7, 9 println(intProgression1.joinToString()) Copy the code
// [1,2] continuous values val closedFloatingPointRange: ClosedFloatingPointRange<Float> = 1f..2f Copy the code
val intArrayOf = intArrayOf(1.2.3.4.5) for (i in 0 until intArrayOf.size) { print("${intArrayOf[i]} ")}// intArrayOf.indices [0,intArrayOf.size) for (i in intArrayOf.indices) { print("${intArrayOf[i]} ")}Copy the code
-
A collection of
-
The immutable set is added
Immutable List
, MutableList MutableList
Map…
Set…
// Elements cannot be added or removed val listOf = listOf(1.2.3) // Elements can be added or removed val mutableListOf = mutableListOf(1.2.3) val mutableMapOf = mutableMapOf("1" to "first"."2" to "Second") for ((x, y) in mutableMapOf) { } val pair = "Hello" to "Kotlin" val pair1 = Pair("Hello"."Kotlin") val first = pair.first val second = pair.second val (x, y) = pair Copy the code
/ / Java implementation List<Integer> integers = Arrays.asList(1.2.3); // Run an error integers.add(1); // The content is mutable integers.set(1.3); // The content is immutable Collections.unmodifiableList(integers) ArrayList arrayList = new ArrayList(); arrayList.add(1); Copy the code
-
Provides a wealth of easy-to-use methods
-
Operator-level support to simplify access to the collection framework
-
-
function
-
The function definitions
Fun (Short for function) Defines the key of a function. Fun is followed by the function name. This is followed by a pair of parentheses that contain the parameters. If there is no return value, you can write Unit. Unit is equivalent to the return value of the Java void function.
fun functionName(arg1: Int, arg2: Int): Int { return 1 } Copy the code
When a function has only one line of code, Kotlin allows you to write a single line of code at the end of the function definition, with an equal sign in the middle.
fun largeNumber(arg1: Int, arg2: Int) = max(arg1, arg2) Copy the code
-
Function vs method
- Methods can be thought of as a special type of function
- Formally, functions that have receivers (Java objects, handles) are methods
-
Type of function
fun foo(a) {} // The type is () -> Unit val a: () -> Unit = {} // Foo is the receiver for the bar method. In Java, this is passed in as the first argument to the function without displaying the call // Function references are similar to function Pointers in C, used for function passing // val kFunction: (Foo, String, Long) -> Long = Foo::bar // val kFunction2: Foo.(String, Long) -> Long = Foo::bar // val kFunction3: Function3
= Foo::bar ,> class Foo{ fun bar(p1:String, p2:Long) : Long { return p1.length + p2 } } val x: (Foo, String, Long) -> Any = Foo::bar yy(x) fun yy(p: (Foo.String.Long) - >Any) { p(Foo(), "Hello".3L) p.invoke(Foo(), "Hello".3L)}Copy the code -
Logical control of a program
Program execution statements are divided into sequential statements, conditional statements and circular statements.
-
Conditional statements
-
If conditional statement
If conditional statements are no different from Java
The if statement in Kotlin has an additional feature over the Java version in that it can have a return value
fun largeNumber(num1: Int, num2: Int): Int { val largeInt = if (num1 > num2) { num1 } else { num2 } return largeInt } Copy the code
-
When conditional statement
When is similar to switch in Java
Switch bug: Only char, byte, short, int, Character, byte, short, Integer, String, or an enum variables can be passed as conditions. In addition, each case must break; otherwise, execute the following cases after executing the current case.
Basic examples:
fun getScore(name: String) = when (name) { "Tom" -> 85 "Jim" -> 77 else -> 0 } Copy the code
Example of type matching:
fun checkNumber(num: Number) = when (num) { is Int -> "Int" is Double -> "Double" else -> "not support type" } Copy the code
Is is a type matching keyword, equivalent to the Instanceof keyword in Java.
For the example of when without arguments, Kotlin uses the **== keyword to determine strings or objects, rather than the Equals () ** method used in Java
fun getScoreNoParam(name: String) = when { name.startsWith("lisa") - >99 name == "Tom" -> 85 name == "Jim" -> 77 else -> 0 } Copy the code
-
-
Looping statements
-
For loop
The For-i loop in Java has been abandoned and the for-each loop in Java has been enhanced to become a for-in loop
Kotlin’s interval is written as follows:
val range = 0.10. / / [0, 10] val range2 = 0 until 10 / / [0, 10) Copy the code
for (i in 0.10.) { print("$i ") // Output 0 1 2 3 4 5 6 7 8 9 10 } Copy the code
Skipping odd elements using the step keyword is equivalent to the Java I = I + 2 operation
for (i in 0 until 10 step 2) { print("$i ") // Output 0, 2, 4, 6, 8 } Copy the code
DownTo defines the descending range
for (i in 10 downTo 0) { print("$i ") // Output 10 9 8 7 6 5 4 3 2 10 } Copy the code
-
The while loop is no different from the Java while loop in both syntax and usage techniques
-
-
-
Object-oriented programming
-
class
File is typically used to write Kotlin top-level functions and extension functions
Class is the Class used to write Kotlin
Classes are decorated with public by default
Example:
class Person { var name = "Tony" var age = 10 fun introduceSelf(a) { println("My name is $name. I am $age years old.")}}Copy the code
Class instantiation:
val person = Person() person.introduceSelf() Copy the code
-
Inheritance and constructors
-
Define the Student class to inherit from Person:
-
Make Person inheritable by adding the open keyword to Person. Any non-abstract class in Kotlin cannot be inherited by default, which is equivalent to declaring the final keyword for a class in Java.
open class Person {... }Copy the code
-
Make Student inherit from Person
class Student : Person() { init{... }... }Copy the code
Why parentheses after Person: Subclass constructors must call superclass constructors.
The constructors in Kotlin are: primary constructor and secondary constructor. The main constructor does not have a function body; Kotlin provides an init structure. Which constructor of the parent class is called by the primary constructor of a subclass is specified by parentheses during inheritance.
-
-
Transform the Person
Person transformation is as follows:
open class Person(val name:String, val age:Int) { fun introduceSelf(a) { println("My name is $name. I am $age years old.")}}Copy the code
Student adjusts accordingly:
class Student(val number: Int.val grade : Int, name:String, age:Int) : Person(name, age) { init{}}Copy the code
The name and age in the Student constructor cannot be declared as var or val, because declaring val or val would be a field of the class.
-
subconstructor
Classes can have only one primary constructor, but they can have more than one secondary constructor. All secondary constructors must call the primary constructor.
The following is an example:
class Student(val number: Int.val grade: Int, name: String, age: Int) : Person(name, age) { constructor(name: String, age: Int) : this(0.0, name, age) { } constructor() : this("Tom".0) {}}Copy the code
The subconstructor is defined by constructor. The instantiation code is as follows:
val student1 = Student() val student2 = Student("Jack".10) val student3 = Student(1527.2."Jerry".21) Copy the code
Class has only secondary constructors, no primary constructors:
class Student : Person { constructor(number: Int, grade: Int, name: String, age: Int) : super(name, age) { } constructor(name: String, age: Int) : this(0.0, name, age) { } constructor() : this("Tom".0) {}}Copy the code
Arguments cannot be declared by var or val in a subconstructor, because the arguments declared by var or val become fields of the class. The secondary constructor does not have to be called, so it is not initialized because it is not called, so it is not allowed to use var or val declarations.
-
-
An abstract class
abstract class AbsClass { abstract fun absMethod(a) // Add open before overwriting open fun overridable(a){} fun nonOverridable(a){}}Copy the code
Method before the open keyword, can be copied
Add the final keyword if the inherited parent class has a method that can be overridden, but does not want the method to be overridden by a subclass
open class SimpleClass(var x: Int.val y: String) : AbsClass() { override fun absMethod(a) {} // Word classes that inherit SimpleClass cannot override this method final override fun overridable(a){}}Copy the code
-
interface
The interfaces in Kotlin are almost identical to those in Java.
-
Interface use:
-
Creating the Study Interface
interface Study { fun readBooks(a) fun doHomework(a) } Copy the code
-
Implementing an interface
class Student(name: String, age: Int) : Person(name, age), Study { override fun readBooks(a){}override fun doHomework(a){}}Copy the code
Those of you familiar with Java know that the extends keyword is inherited, implements is implemented, and Kotlin uses colons separated by commas.
-
Example:
fun main(a) { val student = Student("Jack".10) doStudy(student) } fun doStudy(study: Study) { study.doHomework() study.readBooks() } Copy the code
Because Student implements the Study interface, the Student class can be passed to the doStudy function and then call the methods of the Study interface. This is called interface oriented programming, or polymorphism.
-
-
The default implementation
interface Study { fun readBooks(a) fun doHomework(a) { println("doHomework default implementation")}}Copy the code
Functions implemented by default are optional to implement or not implement. No implementation will use the default implementation logic.
-
Visibility modifier
The modifier Java Kotlin public All classes visible All classes visible (default) private Current class visible Current class visible protected Visible to current class, subclass, and class under the same package The current class and subclass are visible default Classes visible under the same package (default) There is no internal There is no Classes visible in the same module -
property(Kotlin) vs field(Java)
Kotlin property = Java (field + get + set)
If val is qualified, only get
Get + set if var modifier
class Person(age: Int, name: String) { var age: Int = age //property get() { return field } set(value) { println("setAge: $value") field = value } var name: String = name get() { return field // backing field } set(value) { } } Copy the code
Attribute references
// No receiver is bound val ageRef = Person::age val person = Person(18."Bennyhuo") / / bind the receiver val nameRef = person::name ageRef.set(person, 20) nameRef.set("Andyhuo") Copy the code
-
-
Data classes and singleton classes
-
Data classes
Data classes typically need to override equals(), hashCode(), and toString() methods
Equals () determines whether data is equal
HashCode () HashMap, HashSet and other hash-related classes work properly
ToString () clear log output
Example:
data class Cellphone(val brand: String, val price: Double) Copy the code
Declaring data before a class indicates that the class is a data class. Kotlin automatically implements equals(), hashCode(), toString() and other fixed methods that make no real logical sense.
-
Singleton class
There is only one instance globally
object Singleton { fun singletonTest(a) { println("SingletonTest is called")}}Copy the code
use
Singleton.singletonTest() Copy the code
-
-
-
Lambda programming
-
Collection creation and traversal
-
Create a List
listOf<String>("Hello"."world"."this"."is"."kotlin") Copy the code
-
Traverse the List
for (s in listOf) { println(s) } Copy the code
-
The listOf() function creates an immutable collection, while the mutableListOf() function is a mutable collection
val mutableList = mutableListOf<String>("Hello"."world"."this"."is"."kotlin") Copy the code
-
Create a Map
var fruitAndPrice :HashMap<String, Int> = HashMap() fruitAndPrice["Apple"] = 3 val fruitAndIndex = mapOf("Apple" to 1."Banana" to 2."Orange" to 3."pear" to 4."Grape" to 5) Copy the code
-
Traverse Map
for ((fruit, number) in fruitAndIndex) { println("fruit is $fruit, index is $number")}Copy the code
-
-
The functional API for collections
-
Take the word with the longest length
val wordList = listOf<String>("Hello"."world"."this"."is"."kotlin") // When there are no elements in the set, the result is empty val maxByOrNull = wordList.maxByOrNull { it.length } // Empty string is used when the result is empty valresult: String = maxByOrNull ? :"" println(result) Copy the code
-
Lambda is a piece of code that can be passed as an argument, Lambda syntax structure
{parameter name1: Parameter type, parameter name2: Parameter type -> function body}Copy the code
-
Simplified derivation
The maxByOrNull above is just a simple function whose internal implementation iterates through the collection and calls a lambda expression (the collection element is passed into the expression) to get the length of the elements and compare, eventually returning the longest collection element.
-
Lambda expressions as variables
val wordList = listOf<String>("Hello"."world"."this"."is"."kotlin") val function = { fruit: String -> fruit.length } val maxByOrNull = wordList.maxByOrNull(function) Copy the code
-
Pass it directly as a parameter
val maxByOrNull = wordList.maxByOrNull({ fruit: String -> fruit.length }) Copy the code
-
When lambda is the last argument to a function, you can move the lambda expression out of parentheses
val maxByOrNull = wordList.maxByOrNull() { fruit: String -> fruit.length } Copy the code
-
If lambda is the only argument to a function, you can omit the parentheses
val maxByOrNull = wordList.maxByOrNull { fruit: String -> fruit.length } Copy the code
-
Kotlin has an excellent type derivation mechanism, and the argument lists in Lambda expressions don’t actually have to declare parameter types in most cases
val maxByOrNull = wordList.maxByOrNull { fruit -> fruit.length } Copy the code
-
When there is only one argument in the argument list of a Lambda expression, there is no need to declare the argument name, but the IT keyword can be used instead
val maxByOrNull = wordList.maxByOrNull { it.length } Copy the code
-
-
Java functional API usage
Limitation: The functional API can be used when a Java method is called in Kotlin code and the method receives a Single Abstract Java method interface argument. A Java single abstract method interface is one in which there is only one method to implement. If there are multiple methods to implement in an interface, functional apis cannot be used.
Take Runnable for example:
-
Java implementation:
new Thread(new Runnable() { @Override public void run(a) { TODO("Not yet implemented")}});Copy the code
-
Kotlin implementation:
Thread(object : Runnable { override fun run(a) { TODO("Not yet implemented")}})Copy the code
Kotlin discarded the new keyword in favor of the object keyword
Again, this is simplified because Runnable has only one method to implement, without explicitly overwriting the run() method
Thread(Runnable { TODO("Not yet implemented")})Copy the code
We can also omit the interface name if there is only one Java single abstract method interface parameter in the argument list of a Java method
Thread({ TODO("Not yet implemented")})Copy the code
If the Lambda expression is still the only argument to the method, you can also omit the parentheses of the method
Thread { TODO("Not yet implemented")}Copy the code
-
-
-
-
Null pointer check
-
Nullable types
fun doStudy(study: Study) { study.doHomework() study.readBooks() } Copy the code
There is no null pointer risk in this code, because Kotlin defaults to non-null parameters and variables, so the Study parameter passed here must not be null either.
Kotlin has moved null-pointer exception checks up to compile time, so if our program is at risk of null-pointer exceptions, it will report an error at compile time.
Allow null example:
fun doStudy(study: Study?). { if(study ! =null) { study.doHomework() study.readBooks() } } Copy the code
-
Void detection AIDS
-
With the aid of? The. Operator removes the if statement
fun doStudy(study: Study?).{ study? .doHomework() study? .readBooks() }Copy the code
-
? The: operator, which receives an expression on both sides and returns the result of the left expression if the left expression is not empty, or the right expression otherwise
General writing:
val a:String = "a" val c = if (a == null) a else "" Copy the code
? : operator:
valc = a ? :"" Copy the code
The example gets the length of the string
fun getWordLength(word : String) : Int { if (word == null) { return 0 } else { return word.length } } Copy the code
Simplified:
fun getWordLength(word : String?). : Int { returnword? .length ? :0 } Copy the code
-
*Non-empty assertion tool, not recommendedThis is a risky way to write it
fun getWordLength(word : String?). : Int { returnword!! .length }Copy the code
-
Auxiliary tool — let
fun doStudy(study: Study?).{ study? .let { stu -> stu.readBooks() stu.doHomework() } }Copy the code
The let function can handle global nulling, whereas the if statement cannot.
We changed the argument in the doStudy() function to a global variable, which still works fine using the let function, but will prompt an error using the if statement.
The reason for this error is that the value of the global variable can be changed by another thread at any time, and even if nulled, there is no guarantee that the study variable in the if statement is free from null pointer risk.
var student: Student? = Student("Lucy".19) fun study(a) { if(student ! =null) { student.doHomework() student.readBooks() } } Copy the code
-
-
Kotlin small magic
-
String embedded expression
class Student(name: String, age: Int) : Person(name, age), Study { override fun readBooks(a) { println("My name is $name, I'm ${age} years old. I'm reading!")}}Copy the code
-
Function default arguments
fun sing(songName:String = "Pretty Girl", artist:String){}Copy the code
Call:
sing("hello"."jams") // Assign via key-value pairs sing(artist = "lucy") Copy the code
Add default values to main constructors to avoid multiple constructors
class Student(val number: Int = 0, val grade: Int = 0, name: String="Tom", age: Int=10) : Person(name, age), Study { } Copy the code