kotlin learning (1) basic concepts, data object types, control flow, null value inspection, classes and interfaces

Meet Kotlin

insert image description here
Like the java language, kotlin is compiled into bytecode and runs in the JVM virtual machine. The features of the kotlin language depend on kotlin's syntax compiler. Languages ​​similar to kotlin are:

  • Scala: The Big Data Domain Development Language
  • Groovy: a dynamic scripting language based on the JVM platform,Used in Android development to write dependencies, plugins, etc.

In 2019, Google announced that Kotlin has become the first development language for Android, and it is imminent for Android programmers to switch from java to Kotlin.

cross-platform features

language type

Languages ​​are divided into interpreted and compiled:

  • Compiled language, the compiler will compile the source code into a binary file one at a time, and the computer can execute it directly, for exampleC和C++
    • Advantages: It can be run once compiled, no compilation is required during runtime, and the efficiency is high.
    • Disadvantages: Different operating systems require different machine codes, and modifying the code requires recompiling module by module.
  • Interpreted language, when the program is running, the interpreter will parse the source code line by line into binary in real time and execute it in the corresponding virtual machine, for exampleJS、Python
    • Advantages: The platform has good compatibility, and it can run after installing the corresponding virtual machine.
    • Disadvantages: It needs to be interpreted and executed at runtime, and the efficiency is low.

java language type

Java is precisely a half-compiled and half-interpreted hybrid language, but it is more interpreted.

Java first compiles the source program into platform-independent Java bytecode (.class) through the compiler javac, and then interprets and executes the bytecode by the JVM.

How kotlin works

The JVM is only responsible for interpreting and executing the bytecode file.class, regardless of how the bytecode file is generated. Kotlin is based on this principle. It will be compiled into a class before running, and then run by the java virtual machine.

Kotlin不仅能够,还能脱离虚拟机层,直接编译成可以在Windows、Linux和MacOS平台上运行的原生二进制代码,被称为Android领域的Swift

hello world

The entry point of the Kotlin application is the main function main, which can take no parameters and return no value.

fun main() {
    
    
    var str:String = "Hello World"
    println(str)
}

basic concept

program entry

There can be no parameters or a parameter list, but the program entry has no return value.

fun main() {
    
    
}

fun main(args: Array<String>) {
    
    
}

Data and Object Types

In kotlin, the original basic data types in Java are cancelled, and all object types are used.
insert image description here
insert image description here

== and ===

Kotlin provides two ways to compare objects

  • compare objects' structures for equality ( ==or equals)
  • Compare object references for equality===
fun main() {
    
    
//sampleStart
    val a: Int = 100
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    val b: Int = 10000
    val boxedB: Int? = b
    val anotherBoxedB: Int? = b

    println(boxedA === anotherBoxedA) // true
    println(boxedB === anotherBoxedB) // false
//sampleEnd
}

Since the JVM applies memory optimizations to integers from -128 to 127 (Integer), all nullable references to a are actually the same object. But no memory optimization is applied to b, so they are different objects ( ===result is false).

On the other hand, their contents are still equal:

fun main() {
    
    
//sampleStart
    val b: Int = 10000
    println(b == b) // 输出“true”
    val boxedB: Int? = b
    val anotherBoxedB: Int? = b
    println(boxedB == anotherBoxedB) // 输出“true”
//sampleEnd
}

explicit number conversion

Smaller types in Kotlin cannot be implicitly converted to larger types, which means that assigning Bytea type to a Intvariable must be explicitly converted:

fun main() {
    
    
	val b : Byte = 1

	val i1: Int = b.toInt();
}

All numeric types support conversion to other types:

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

In many cases, explicit type conversion is not needed, because the type will be inferred from the context, and the arithmetic operation will be overloaded to do the appropriate conversion, for example:

val l = 1L + 3 // Long + Int => Long

floating point type

Kotlin provides floating-point types Float and Double types, which have different sizes and provide storage for floating-point numbers of two different precisions:
insert image description here

  1. For variables initialized with decimals, the compiler infers Doublethe type:
val pi = 3.14  // Double
// val one: Double = 1 // 错误:类型不匹配
val oneDouble = 1.0 //Double
  1. To explicitly specify a value as Floata type, add for Fsuffix, and such a value will be rounded if it contains more than 6~7 decimal digits:
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float,实际值为 2.7182817
  1. Unlike other languages,Numbers in Kotlin do not have implicit widening conversions, for example functions with Double parameters can only be called on Double values, not on Float, Int or other numeric values
fun main() {
    
    
    fun printDouble(d: Double) {
    
     print(d) }

    val i = 1    
    val d = 1.0
    val f = 1.0f 

    printDouble(d)
//    printDouble(i) // 错误:类型不匹配
//    printDouble(f) // 错误:类型不匹配
}

bit operation

Kotlin provides a set of bitwise operations for integer types Intand .Long

  • shl(bits) – signed left shift (shift left)
  • shr(bits) – signed right shift (shift right)
  • ushr(bits) – unsigned shift right
  • and(bits) – bit and
  • or(bits) – bits or
  • xor(bits) – bit exclusive or
  • inv() – bitwise inverse

Any

Any is the root type of a non-empty type, similar to Object as the top level of the Java class hierarchy. When Any类型是Kotlin中所有非空类型的超类。Any is used in a Kotlin function, it will be compiled into an Object in the Java bytecode.

Any?类型是Kotlin所有类型的根类
At the bottom of the Kotlin type hierarchy is the Nothing type. The type structure diagram is as follows:
insert image description here

Unit

UnitThe function is similar to that in Java void, but the meaning of void is that there is no return value. Kotlin is more thorough in facing objects. The return value without return value should also be an object, so there is Unit. If this concept is not
explicitly returnspecified Return value, then the compiler will automatically add the return Unit:

fun returnUnit() : Unit {
    
    
	return Unit
}

Nothing

UnitThe meaning of this function is no return value.
However Nothing, it isPrompt the developer that this function will not return, such as it 可能是抛异常, does not return, or拥有无限循环的函数。

Function 1: The return value of the function that throws an exception

fun throwOnNameNull() : Nothing {
    
    
	throw NullPointerException("姓名不能为空!")
}

In addition to the use of throwing an exception above, the ==Nothing object is also a common subtype of all object types. ==In this way, Nothing is actually multiple inheritance, that is, the inheritance rules are extended in Kotlin, 类不允许多重继承,Nothing除外because the constructor of Nothing is private, it will not have any instance objects, so his multiple inheritance will not bring of any actual risk.

Based on the fact that Nothing is a subclass of all types, it can be combined with generics to build a generic empty List, as follows:

insert image description here
Function 2: As a generic, blank temporary filling for generic variables

Function 3: Nothing makes kotlin more complete at the grammatical level.

In the underlying logic of kotlin, throw has a return value, and its return value type is Nothing,
so the following writing is legal:

val nothing: Nothing = throw RuntimeException("抛异常!"

Because Nothing is a subclass of all types, all of the following works:

var _name: String? = null
val name: String = _name ?:throw NullPointerException("_name 运行时不能为空!")

declare variable

Kotlin uses keywords varto declare variable variables, and the variable name and variable type are :separated by a colon. This scripting language, like Python, does not require ;an ending.

insert image description here
var: Variable variable, corresponding to Java's 非final variable

var b = 1

val: Immutable variables, corresponding to Java finalvariables

val a = 1

The above declaration process does not use a colon :to indicate the type, because Kotlin has a class derivation mechanism, the above asum bwill be regarded as by default according to the assignment resultInt

Read-only variable val and mutable variable var

  • var: Indicates a modifiable variable
  • val: indicates a read-only variable

Mainly the difference between non-final and final.

View Kotlin bytecode

insert image description here

fun (method/function)

The fun keyword is used to declare methods:
Below is a method that takes 2 Int parameters and returns an Int.

fun sum(a: Int, b: Int): Int {
    
    
	return a + b;
}

The method body can be an expression whose return value can be inferred:

fun sum (a: Int, b: Int) = a + b 

The method can have no return value, or return a meaningless value (Unit)

fun printSum(a: Int, b:Int): Unit {
    
    
	println("sum of $a and $b is ${
      
      a + b}")
}

Among them, Unit can also be ignored;

fun printSum(a: Int, b:Int) {
    
    
	println("sum of $a and $b is ${
      
      a + b}")
}

Function parameter default values

Kotlin supports functions with default values, which are used as follows:

fun main() {
    
    
	myPrint(1)
	myPrint(1, "lalala")
}

fun myPrint(value : Int, str : String = "hello") {
    
    
	println("num is $value, str is $str")
}

If the value wants to be the default value, it will be saved, because the first parameter passed in must be of type Int. The incoming string type will not match:

fun main() {
    
    
    myPrint("zjm")//报错
}

fun myPrint(value: Int = 100, str: String) {
    
    
    println("num is $value, str is $str")
}

Kotlin's function parameter passing supports the same key-value pair parameter passing as Python, so that the order of parameters can be changed:

fun main() {
    
    
    myPrint(str = "zjm") //正确调用
}

fun myPrint(value: Int = 100, str: String) {
    
    
    println("num is $value, str is $str")
}

class (class)

Define a
class The attributes of a class can be placed in the definition or inside the class, such as the following:

class Rectangle(var height: Double, var length: Double) {
    
    
	var perimeter = (height + length) * 2
}

var rectangle = Rectangle(5.0, 2.0)
println("The perimeter is ${
      
      rectangle.perimeter}")

For kotlin version 1.4.30, the inheritance of a class is :represented by a colon. The class is final by default and cannot be inherited. In order to make the class inheritable, use openkeywords and place them in front of the class:

open class Rectangle(var height: Double, var length: Double) {
    
    
	var perimeter = (height + length) * 2
}

$(string template)

Using $templates that can help define strings, translate string variables.
To use variables directly $, to use expressions, curly braces are required${}

Below is an example:

var a = 1
val S1 = "a is $a"
println(S1)
a = 2;
val S2 = "${
      
      S1.replace("is", "was")}, but now is $a"
println(S2)

result:

a is 1
a was 1, but now is 2

control flow

if-else (conditional expression)

fun getMax(a: Int, b: Int): Int {
    
    
	if (a > b) {
    
    
		return a
	} else {
    
    
		return b
	}
}

The if above can also be written as an expression, similar to the ternary operator:

fun getMax(a: Int, b: Int) = if (a > b) a else b

cycle

for

  1. use inkeywords
  2. use subscript
val items = listof("apple", "banana", "kiwifruit")
for (item in items) {
    
    
	println(item)
}

for (index in item.indices) {
    
    
	println("item at $index is ${
      
      items[index]}")
}
// 闭区间打印[1, 3]
// 输出 1,2,3
for (i in 1..3) {
    
    
	println(i)
}
// 从7到0,降序,步长为2
// 输出 7,5,3,1
for (i in 7 downTo 0 step 2) {
    
    
	println(i)
}

for- inThe default range is a double-closed range. If you want to use left-closed and right-open, you need to use keywordsuntil

fun main() {
    
    
	for (i in 0 until 10) {
    
    
		
	}
}

while

val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
    
    
    println("item at $index is ${
      
      items[index++]}")
}

result:

item at 0 is apple
item at 1 is banana
item at 2 is kiwifruit

when expression

when expression looks a bit like swich case in java.

fun describe(obj: Any): String = 
	when (obj) {
    
    
		1 -> "One"
		"Hello" -> "Greeting"
		is Long -> "Long"
		!is String -> "Not a String"
		else -> "Unknown"
	}

abnormal

Exception class Throwable

All exception classes in Kotlin inherit from classes and throw exceptions Throwableusing expressions:throw

fun main() {
    
    
//sampleStart
    throw Exception("Hi There!")
//sampleEnd
}

Use try ... catch expressions to catch exceptions:

try {
    
    
    // 一些代码
} catch (e: SomeException) {
    
    
    // 处理程序
} finally {
    
    
    // 可选的 finally 块
}

There can be zero or more catch blocks, and finally blocks can be omitted. But at least one catch and finally block is required.

Null values ​​and null value checks

A variable that can be null requires a question mark after it ?.
For example, the method below returns Int or null

fun parseInt(str: String) : Int? {
    
    
	...
}

safe call operator?.

This operator allows you to combine a null check and a method call into one operation. For example

s?.toUpperCase()

Is equivalent to the following writing:

if (s!=null) {
    
    
	s.toUpperCase
} else {
    
    
	null
}

Safe calls can be used not only to call methods, but also to access properties.

If you have multiple properties of nullable types in your object, it is often convenient to use multiple safe calls in the same expression. Using this operator, you can access deeper properties in one line of code without additional checks. as follows:

class Address(val streetAddress:String,val code:Int,val city:String)
class Company(val name:String,val address: Address?)
class Person(val name:String,val company: Company?)

fun Person.cityName():String{
    
    
    val city = this.company?.address?.city
    return if (city != null) city else "unKnown"
}

Elvis operator?:

The Elvis operator takes two operands, and if the first operand is not null, the result of the operation is the first operand, otherwise the result of the operation is the second operand.
For example, below, if s is not empty, str is s, otherwise str is an empty string object

fun foo(s: String) {
    
    
	val str: String = s?:""
}

The Elvis operator is often used with the safe call operator to replace the null returned by calling a method on a null object with a value. Let's simplify the previous code:

fun Person.cityName():String {
    
    
	val city = this.company?.address?.city
	return city ?: "unKnown"
}

There is a scene in kotlin where the Elvis operator is very suitable. Operations like return and throw are actually expressions, so they can be written on the right side of the Elvis operator. When the value to the left of the operator is null, the function immediately throws an exception.

fun printPersonName(person : Person) {
    
    
	val name = person.name? : throw IllegalArgumetException("no name")
	println(name)
}

Follow the conversionas?

as is a Kotlin operator used to convert types, just like java types, if the value being converted is not the type you are trying to convert. A ClassCastException will be thrown.

as?operator attempts to convert the value to the specified type,Returns null if the value is not of the appropriate type. we canUse this operator with Elvis, such as implementing the equals method of the Person class

class Person(val name:String, val company: Company?) {
    
    
	override fun equals(other: Any?): Boolean {
    
    
		val otherPerson = other as? Person ?: return false
		return otherPerson.name && other.company == company
	}
}

non-null assertion!!

Non-null assertion is the most simple and direct tool provided by kotlin to deal with nullable type values. Use double exclamation marks to indicate that any value can be converted to a non-null type. An exception will be thrown if a non-null assertion is made on null.

fun ignoreNull(s:String){
    
    
    val notNull = s!!
    println(notNull.length)
}

If s is null in this function, an exception will be thrown at runtime. The place where the exception is thrown is the line where the not-null assertion is made, not the line where the value is then attempted to be used.

Because the information of the exception call stack trace only shows which line the exception occurred on,!!To make trace information more explicit, avoid multiple assertions on the same line at the end .

let function

The let function makes it easier to work with nullable expressions. Used together with the safe call operator, it allows you to evaluate an expression, check if the result is null, and store the result in a variable, all of which all in the same simple expression.

What the let function does is to turn an object that calls it into a parameter of a lambda expression. Combined with the safe call syntax, it can effectively transform the nullable object that calls the let function into a non-null type. In other words,A let that is safe to call will only execute the lambda if the expression is not null.

s?.let {
    
     
    print(s.length)
}

If you want to achieve the above effect, the Java code is as follows:

public static final void ignoreNull(@Nullable String s) {
    
    
	if (s != null) {
    
    
		System.out.print(s.length());
	}
}

lateinit Lazy initialization properties

Kotlin usually requires that all properties be initialized in the constructor. If a property is a non-null property, a non-null initialization value must be provided, otherwise a nullable type must be used. If this is done, the property needs or asserts every time it is null检查accessed !!.

class MyService {
    
    
	fun performAction():String = "foo"
}

class MyTest{
    
    
	private var myService:MyService?=null
	
	fun test() {
    
    
		myService!!.performAction()
	}
}

It can be used lateinitto delay the initialization of myService. The properties of delayed initialization are all var. Although it is a non-null type, it does not need to be initialized in the constructor.

class MyService{
    
    
    fun performAction():String = "foo"
}

class MyTest{
    
    
    // 声明一个不需要初始化器的非空类型的属性
    private lateinit var myService:MyService

    fun test(){
    
    
        myService.performAction()
    }
}

Nullable type extension

The Kotlin standard library defines two extension functions of String isEmpty, isBlank
isNullOrBlank, to determine whether it is an empty string or whether it contains only blank characters. This extension function can allow the receiver to be called as null:

fun  verifyInput(input:String?){
    
    
    if (input.isNullOrBlank()){
    
    
        print("it is not ok")
    }
}

Safe access is not required because possible null values ​​are handled internally by the function:

@kotlin.internal.InlineOnly
public inline fun CharSequence?.isNullOrBlank(): Boolean {
    
    
    contract {
    
    
        returns(false) implies (this@isNullOrBlank != null)
    }

    return this == null || this.isBlank()
}

Nullability of type parameters

The type parameters of all generic classes and generic functions in Kotlin are nullable by default, in which case null is allowed for declarations that use type parameters as types, even though the type parameter T does not end with a question mark.

fun <T> printSomething(t:T){
    
    
    // 因为 t 可能为 null,所以必须使用安全调用
    print(t?.hashCode())
}
// 传入 null 进行调用
printSomething(null)

In this method, the deduced type of the type parameter T is the nullable type Any?, so the actual parameter t still allows null even though it does not end with a question mark.

If the type parameter is non-null, you must specify a non-null upper bound for it, so that generics will reject nullable values ​​​​as actual parameters.

// 这样的话,T 就不是可空的
fun <T:Any> printSomething1(t:T){
    
    
    print(t.hashCode())
}

is: type checking and automatic conversion

It is usedis to check whether an object is a certain type. If the type of an immutable variable is determined, then no explicit conversion is required when using it later:

fun getStringLength(obj: Any): Int? {
    
    
	if (obj is String) {
    
    
		// 这里obj已经转为String类型
		return obj.length
	}
	return null
}

Or !iswrite it in reverse:

fun getStringLength(obj: Any): Int? {
    
    
	if (obj !is String) return null

	return obj.length
}

classes and objects

Create a Person class:

class Person {
    
    
	var name = ""
	var age = 0
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

inherit

The default class in Kotlin is not inheritable (that is, it is modified by final). If you want this class to be inherited, you need classto use openthe keyword before it.

open class Person {
    
    
	var name = ""
	var age = 0
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

Declare a Student class to inherit from the Person class. In kotlin, the inheritance uses :the construction of the parent class:

class Student : Person() {
    
    
	var number = ""
	var grade = 0
	fun study() {
    
    
		println("$name is studying")
	}
}

structure

The structure is divided into main structure and secondary structure

main structure

The main construction is written directly after the class

class Student(val number: String, val grade: Int) : Person() {
    
    
	fun study() {
    
    
		println("$name is studying")
	}
}

Create a Student object:

val student = Student("1234", 90)

Because the parent class Person also has name and age attributes, a main structure is also constructed for the parent class Person:

open class Person(val name : String, val age : Int) {
    
    
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

At this time, Student reports an error, because when inheriting Person, the Person() no-argument construction is used later, and above we have modified Person's no-argument construction, so there is no no-argument construction.

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age){
    
    
	fun study() {
    
    
		println("$name is studying")
	}
}

Construct a Student class at this time;

val student = Student("zjm", 20, "1234", 90)

What if construction requires special handling? Kotlin provides inita structure, and the logic of the main structure can be processed in init, such as:

open class Person(val name : String, val age : Int) {
    
    
	init {
    
    
		println("name is $name")
		println("age is $age")
	}
}

The above modifications are all 主构造, what if the class needs multiple constructs? Need help at this time次构造

secondary structure

Secondary construction, use constructorthe keyword to declare the constructor, :followed by this(), that isThe essence of the secondary constructor is to call the primary constructor
Implement the following two substructures:

  1. The construction of three parameters, name, age, number, grade does not pass parameters, the default is 0.
  2. No parameter construction: Int defaults to 0, String defaults to an empty string
class Student(name: String,  age: Int, var number: String, var grade: Int) : Person(name, age){
    
    
    fun study() {
    
    
        println("$name is studying")
    }
    constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {
    
    

    }
    
    constructor() : this("", 0, "", 0) {
    
    
        
    }
}

// 调用
val student = Student("lzy", 23, "1234", 90)
val student1 = Student("lzy", 23, "121");
val student2 = Student()

permission modifier

The difference between Java and kotlin is as follows:
insert image description here
kotlin introduced internal, abandoneddefault

Data classes and singleton classes

data class

The data class only deals with data-related, Java Beansimilar to and usually needs to implement its get, set, hashcode, equal, toStringand other methods.

The following implementation UserBeanincludes: id, name, pwdattributes.
Java:

public class UserBean {
    
    
    private String id;
    private String name;
    private String pwd;

    public UserBean() {
    
    

    }

    public UserBean(String id, String name, String pwd) {
    
    
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    @Override
    public boolean equals(Object o) {
    
    
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserBean userBean = (UserBean) o;
        return Objects.equals(id, userBean.id) && Objects.equals(name, userBean.name) && Objects.equals(pwd, userBean.pwd);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(id, name, pwd);
    }

    @Override
    public String toString() {
    
    
        return "UserBean{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }

    public String getId() {
    
    
        return id;
    }

    public void setId(String id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getPwd() {
    
    
        return pwd;
    }

    public void setPwd(String pwd) {
    
    
        this.pwd = pwd;
    }
}

Writing this class in Kotlin will become very simple. Create a new ktfile and choose as follows:
insert image description here
one line of code can be done, and kotlin will automatically implement the above method.
Double-click on Shift to call up 工具搜索, search show kotlin ByteCode, and view the kotlin bytecode:
the corresponding Java Bean class is indeed created
insert image description here

singleton class

At present, the most widely used singleton mode (static inner class) in Java is implemented as follows:

public class SingleInstance {
    
    
	private SingleInstance() {
    
    
	}
	private static class SingleHolder {
    
    
		private static final SingleInstance INSTANCE = new SingleInstance();
	}

	public static SingleInstance getInstance() {
    
    
		return SingleHolder.INSTANCE;
	}
	public void test() {
    
    
	}
}

KotlinTo create a singleton class in , you need to select the Object
insert image description here
generated code as follows:

object SingleInstance {
    
    
	fun test () {
    
    
	}
}

The corresponding javafiles are as follows, similar to the above-mentioned most used javasingleton implementation:

public final class Singleton {
    
    
   @NotNull
   public static final Singleton INSTANCE;

   public final void test() {
    
    
   }

   private Singleton() {
    
    
   }

   static {
    
    
      Singleton var0 = new Singleton();
      INSTANCE = var0;
   }
}

Use as follows:

fun main() {
    
    
    Singleton.test() //对应的java代码为Singleton.INSTANCE.test();
}

enum class

The most basic application scenario of an enumeration class is to implement a type-safe enumeration:

enum class Direction {
    
    
    NORTH, SOUTH, WEST, EAST
}

Each enumeration constant is an object. Enumeration constants are separated by commas.

Because every enumeration is an instance of the enumeration class, it can be initialized like this:

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

Every enumeration constant also has these two properties: name and ordinal, to get its name and position (from 0) in the enumeration class declaration:

enum class RGB {
    
     RED, GREEN, BLUE }

fun main() {
    
    
    //sampleStart
    println(RGB.RED.name) // prints RED
    println(RGB.RED.ordinal) // prints 0
    //sampleEnd
}

Sealed class sealed

Define the Result interface:

interface Result 
class Success(val msg: String) : Result
class Failure(val msg: String) : Result

Define a method:

fun getResultMsg(result: Result) = when(result) {
    
    
    is Success -> result.msg
    is Failure -> result.error.message
    else -> throw IllegalArgumentException()
}

Due to the nature of Kotlin, else must be written, but the above code is only possible in two cases. else is purely redundant. If the programmer neglects to pass in the UnKown class, the APP will crash.

In order to solve the above problems, it is necessary to rely on sealedthe sealed class and its subclasses can only be defined at the top level of the same file, and cannot be nested in other classes

sealed class Result
class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()
fun getResultMsg(result: Result) = when(result) {
    
    
    is Success -> result.msg
    is Failure -> result.error.message
}

interface

Define an interface:

interface Study {
    
    
    fun study()
    fun readBooks()
    fun doHomeWork()
    fun exercise()
}

interface inheritance

The inherited interface only needs to be used behind the class ,and implement Studyall the declared functions:

class GoodStudent(name: String, age: Int, var ID: String, var grade: Int) : Person(name, age) , Study{
    
    
    override fun study() {
    
    
        TODO("Not yet implemented")
    }

    override fun readBooks() {
    
    
        TODO("Not yet implemented")
    }

    override fun doHomeWork() {
    
    
        TODO("Not yet implemented")
    }

    override fun exercise() {
    
    
        TODO("Not yet implemented")
    }

}

Kotlin supports the default implementation of interface methods, and JDK1.8 later also supports this function. If the method has a default implementation, the inherited class does not have to implement this method.

interface Study {
    
    
    fun study() {
    
    
        println("study")
    }
    fun readBooks()
    fun doHomework()
}

resolve overlay conflicts

When implementing multiple interfaces, you may encounter the problem of inheriting multiple implementations of the same method:

interface A {
    
    
    fun foo() {
    
     print("A") }
    fun bar()
}

interface B {
    
    
    fun foo() {
    
     print("B") }
    fun bar() {
    
     print("bar") }
}

class C : A {
    
    
    override fun bar() {
    
     print("bar") }
}

class D : A, B {
    
    
    override fun foo() {
    
    
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
    
    
        super<B>.bar()
    }
}

In the above example, interfaces A and B both define methods foo() and bar(). Both implement foo(), but only B implements bar() (bar() is not marked as abstract in A because it defaults to abstract when there is no method body in an interface). Now, if you implement a concrete class C of A, you must override bar() and implement this abstract method.

However, if you derive D from A and B, you need to implement all the methods inherited from multiple interfaces and indicate how D should implement them. This rule applies both to methods inheriting a single implementation ( bar() ) and to methods inheriting multiple implementations ( foo() ).

Functional Interface (SAM) Interface

An interface with only one abstract method is called a functional interface or a single abstract method (SAM) interface. A functional interface can have multiple non-abstract members, but only one abstract member.

For example, there is this Kotlin functional interface:

fun interface IntPredicate {
    
    
   fun accept(i: Int): Boolean
}

If you don't use SAM conversion, then you need to write code like this:

// 创建一个类的实例
val isEven = object : IntPredicate {
    
    
   override fun accept(i: Int): Boolean {
    
    
       return i % 2 == 0
   }
}

By taking advantage of Kotlin's SAM conversion, the following equivalent code can be changed instead:

fun interface IntPredicate {
    
    
   fun accept(i: Int): Boolean
}

val isEven = IntPredicate {
    
     it % 2 == 0 }

fun main() {
    
    
   println("Is 7 even? - ${
      
      isEven.accept(7)}")
}

Guess you like

Origin blog.csdn.net/baiduwaimai/article/details/131101935