网站建设合同模式,wordpress商城 淘宝客,公司网站如何推广,国外做外汇网站交流NULL检查机制 Kotlin的空安全设计对于声明可为空的参数#xff0c;在使用是进行空判断处理#xff0c;有两种处理方式#xff0c;字段后加 !! 像 java 一样抛出空异常#xff0c;另外字段后面加 ? 可不做处理返回值为 null 或者配合 ?: 做空判断处理。 //类型后面加 ? 表…NULL检查机制 Kotlin的空安全设计对于声明可为空的参数在使用是进行空判断处理有两种处理方式字段后加 !! 像 java 一样抛出空异常另外字段后面加 ? 可不做处理返回值为 null 或者配合 ?: 做空判断处理。 //类型后面加 ? 表示可为空val age: String?  null//抛出空指针异常val ages  age!!.toInt()//不做处理返回 nullval ages1  age?.toInt()//age 为空返回 -1val ages2  age?.toInt() ?: -1 类型检测及自动类型转换 
我们可以使用 is 运算符检测一个表达式是否某类型的一个实例类似于 java 中的 instanceof关键字 
fun getStringLength(obj: Any): Int? {if (obj !is String) return null//在这个分支中‘obj’ 的类型会被自动转换为 ‘String’return obj.length
} 
区间 区间表达式由具有操作符形式 .. 的rangeTo 函数辅以 in 和 !in 形成。 for (i in 1..4) print(i) //输出 1234for (i in 4..1) print(i) // 什么都不输出//使用 step 指定步长for (i in 1..4 step 2) print(i) //设置跳过 2 步 执行输出 13for (i in 4 downTo 1 step 2) print(i)//输出 42//使用 until 函数排除结束元素for (i in 1 until 10) print(i) // i in [1,10) 排除了 10 输出: 123456789 
字面常量 val int  123 // 十进制val int1  123L //长整型以大写的 L 结尾val data  0x0f //16进制以 0x 开头: 0x0Fval data2  0b00001011 //2 进制以 0b 开头//Doubles 默认写法 123.5 123.5e10val double  123.5val double2  123.5e10val floats  123.5f//可以使用下划线使数字常量更易读val oneMillion: Int  1_000_100 
比较两个数字 
Kotlin 中没有基础数据类型只有封装的数字类型你每定义的一个变量其实 Kotlin 帮你封装了一个对象这样可以保证不会出现空指针。数字类型也一样所以在比较两个数字的时候就有比较数据大小和比较两个对象是否相同的区别。 
在 Kotlin 中三个等号  表示比较对象地址两个  表示比较两个值大小。 
fun test4() {val a  1000println(a  a) //值相等对象地址相等 输出true//经过了装箱创建了两个不同的对象val boxedA: Int?  aval anotherBoxedA: Int?  a//虽然经过了装箱但是值是相等的println(boxedA  anotherBoxedA) //值相等对象地址不一样 输出falseprintln(boxedA  anotherBoxedA) //值相等 输出true
} 
类型转换 
由于不同的表示方式较小类型并不是较大类型的子类型较小的类型不能隐式转换较大的类型这意味着在不进行显式转换的情况下沃恩不能把 Byte 型值赋给一个 Int 变量 
fun test5(){val b: Byte  1// OK 字面值是静态检测的val i:Int  b//错误
} 
位操作符 
对于 Int 和 Long 类型还有一系列的位操作符可以使用 
字符 Char 
fun decimalDigitValue(c: Char): Int {if (c !in 0..9)throw IllegalArgumentException(Out of range)return c.toInt() - 0.toInt() // 显式转换为数字
} 
数组 
数组用类 Array 实现并且还有一个 size 属性及 get 和 set 方法由于使用  [] 重载了 get 和 set 方法所以我们可以通过下标很方便的获取或者设置数组对应位置的值。 
数组的创建两种方式一种是使用函数 arrayOf(); 另外一种是使用工厂函数如下所示我们分别是两种方式创建了两个数组 
fun test6() {val a  arrayOf(1, 2, 3) //输出[1,2,3]for (i in a) print(i)print(-------------------------)val b  Array(3) { i - (i * 2) }//输出 [0,2,4]for (i in b) print(i)
} 
字符串 
Kotlin支持三个引号 “”” 扩起来的字符串支持多行字符串.String 可以通过 trimMargin() 方法来删除多余的空白。 
fun test7() {val text  多行字符串多行字符串println(text)//输出有一些前置空格
} 
fun test7() {val text  |多行字符串|多行字符串.trimMargin()print(text)//输出有一些前置空格//print(text.trimMargin())
} 
字符串模版 
字符串可以包含模版表达式即一些小段代码会求值并把结果合并到字符串中模版表达式以美元符 $ 开头由一个简单的名字构成 
fun test8() {val i  10val s  i  $iprint(s)
} 
或者用花括号括起来的任意表达式 
fun test8() {val i  10val s  i  $iprintln(s)val s2  runoobval str  $s2.length is ${s2.length}println(str)
} 
IF表达式 
fun test9() {val a  1val b  2val max  if (a  b) a else bprintln(max)
} 
使用区间 
fun test10() {val x  1 //输出x 在区间内if (x in 1..9) {println(x 在区间内)}
} 
When 表达式 
when 将它的参数和所有的分支条件顺序比较直到某个分支满足条件。 
when 既可以被当做表达式使用也可以被当做语句使用。如果它被当做表达式符合条件的分支的值就是整个表达式的值如果当做语句使用则忽略个别分支的值。 
when 类似其他语言的 switch 操作符其最简单的形式如下 
fun test11(){val x  1 //输出x  1when(x){1 - print(x  1)else -{print(x 不是 1也不是 2)}}
} 
when 中使用 in 运算符来判断集合内是否包含某实例 
fun test12() {val items  setOf(apple, banana, kiwi)when {orange in items - println(juicy)apple in items - println(apple is fine too)}//输出apple is fine too
} 
For 循环 
for 循环可以对任何提供迭代器 iterator 的对象进行遍历语法如下 
for (item in collection) print( item ) 
fun test13() {val items  listOf(apple, banana, kiwi)for (item in items) println(item)println(--------------------------)for (index in items.indices)println(item at $index is ${items[index]})println(--------------------------)for ((index, value) in items.withIndex())println(item at $index is $value)
} 
while 与 do...while 循环 
while 是最基本的循环它的结构为 
while(布尔表达式) { //循环内容 
} 
返回和跳转 
Kotlin 有三种结构化跳转表达式 
return 默认从最直接包围它的函数或者匿名函数返回 
break 终止最直接包围它的循环 
continue 继续下一次最直接包围它的循环 
fun test14() {for (i in 1..10) {if (i  3) continue// i 为 3 时跳出当前循环继续下一次循环print(i)if (i  5) break}//输出12456
} 
Kotlin 类和对象 
类定义 
Kotlin 类可以包含构造函数和初始化代码块、函数、属性、内部类、对象声明 
Kotlin 中使用关键字 class 声明类声明紧跟类名 
class Runoob{ //大括号内是类的体构成 
} 
类属性 
class Runoob{ var name:String  Runoob 
} 
//Kotlin 中的类可以有一个 主构造器以及一个或多个次构造器主构造器是类头部的一部分位于类名称之后
class Person constructor(firstName: String) {}//如果主构造器没有任何注解也没有任何可见度修饰符那么 constructor关键字可以省略
class Person2(firstName: String) {} 
getter 和 setter 
fun test15() {var person  Person3()println(person.lastName:${person.lastName})person.no  99println(no:${person.no})//输出// person.lastName:LONG//no:-1
}class Person3 {var lastName  longget()  field.toUpperCase()var no  100set(value) {field  if (value  10) {value} else {-1}}
}lateinit 
非空属性必须在定义的时候初始化kotlin提供了一种可以延迟初始化的方案使用 lateinit 关键字描述属性 
主构造器 
主构造器中不能包含任何代码初始化代码可以放在初始哈代码段中初始化代码段使用 init 关键字作为前缀。 
//Kotlin 中的类可以有一个 主构造器以及一个或多个次构造器主构造器是类头部的一部分位于类名称之后
class Person constructor(firstName: String) {init {println(firstName is $firstName)}
} 
次构造函数 
如果类有主构造函数每个次构造函数都要或直接或间接通过另外一个次构造函数代理主构造函数。在同一个类中代理另外一个次构造函数使用 this 关键字 
class Person4(val name: String) {constructor(name: String, age: Int) : this(name) {}
} 
//私有构造函数
class Customer private constructor(){} 
抽象 
抽象是面向对象编程的特征之一类本身或类中的部分成员都可以声明为 abstract 的。抽象成员在类中不存在具体的视线。 
注意无需对抽象类或抽象成员标注 open 注解。 
open class Base{open fun f(){}
}abstract class Derived:Base(){override fun f() { }
} 
嵌套类 
class Outer {private val bar  1class Nested {fun foo()  2}
}fun test17() {val demo  Outer.Nested().foo() //调用格式 外部类.嵌套类().嵌套类方法/属性println(demo)//输出 2
} 
内部类 
内部类使用 inner 关键字来表示 
内部类会带有一个对外部类的对象引用所以内部类可以访问外部类成员属性和成员函数。 
class Outer2 {private val bar  1var v  成员属性/*嵌套内部类*/inner class Inner {fun foo()  bar//访问外部类成员fun innerTest() {var o  thisOuter2println(内部类可以引用外部类的成员 例如${o.v})}}
}fun test18() {val demo  Outer2().Inner().foo()println(demo)val demo2  Outer2().Inner().innerTest()println(demo2) // 内部类可以引用外部类的成员例如成员属性
} 
为了消除歧义要访问来自外部作用域的 this 我们使用 thislabel, 使用 label 是一个代指 this 来源的标签。 
匿名内部类 
使用对象表达式来创建匿名内部类 
class Test {var v  成员属性fun setInterFace(test: TestInterFace) {test.test()}
}/*** 定义接口*/
interface TestInterFace {fun test()
}fun test19() {var test  Test()/*** 采用对象表达式来创建接口对象即匿名内部类的实例*/test.setInterFace(object : TestInterFace {override fun test() {println(对象表达式创建匿名内部类的实例)}})
} 
类的修饰符 
类的修饰符包括 classModifier 和 acessModifier classModifier 类属性修饰符表示类本身特性abstract    //抽象类
final       //类不可集成默认属性
enum        //枚举类
open        //类可继承类默认是 final
anotation   //注解类 accessModifier 访问权限修饰符private     //仅在同一个文件中可见
protected   //同一个文件夹中或子类可见
public      // 所有调用的地方可见
internal    // 同一个模块中可见 Kotlin 继承 
Kotlin 中所有类都继承该 Any类它是所有类的超类对于没有超类型声明的类是默认超类 
class Example //从 Any 隐式继承 
构造函数 
子类有主构造函数 
如果子类有主构造函数则基类必须在主构造函数中立即初始化 
class Student(firstName: String) :Example(firstName){}open class Example constructor(firstName: String){} 
子类没有主构造函数 
如果子类没有主构造函数则必须在每个二级构造函数中用 super 关键字初始化基类或者在代理另一个构造函数。初始化基类时可以调用基类的不同构造方法。 
open class Student(firstName: String) : Example(firstName) {}open class Example constructor(firstName: String) {}class Student2 : Student {constructor(firstName: String) : super(firstName) {}
} 
重写 
在基类中使用 fun 声明函数时此函数默认为 final 修饰不能被子类重写。如果允许子类重写该函数那么就要手动添加 open 修饰它。子类重新方法使用 override 关键词 
/*** 用户基类*/
open class Person5 {open fun study() {println(我毕业了)}
}/*** 子类继承*/
class Student3 : Person5() {override fun study() {//重写方法super.study()println(我在读大学)}
}fun test20() {val s  Student3()s.study()
} 
如果有多个相同的方法继承或者实现自其他类如A类B类则必须要重写该方法使用 super 泛型去选择性地调用父类的实现。 
interface B {fun f() {println(B)}
}class C : A(), B {override fun f() {superA.f()//调用 A.f()superB.f()//调用 B.f()}
}fun test21() {val c  C()c.f()//输出 A B
} 
属性重写 
属性重写使用 override 关键字属性必须具有兼容类型每一个声明的属性都可以通过初始化程序或者 getter 方法被重写 
open class Foo {open val x  100
}class Bar1 : Foo() {override val x: Intget()  super.x
} Kotlin 接口 
Kotlin 接口与 java8 类似使用 interface 关键字定义接口允许方法有默认实现。 
interface MyInterface {fun bar()  //未实现fun foo() { //已实现//可选的方法体println(foo)}
} 实现接口 
一个类或者对象可以实现一个或者多个接口 
interface MyInterface {fun bar()  //未实现fun foo() { //已实现//可选的方法体println(foo)}
}class Child : MyInterface {override fun bar() {TODO(Not yet implemented)}接口中的属性 
接口中的属性只能是抽象的不允许初始值接口不会保存属性值实现接口时必须重写属性 
interface MyInterface2 {var name: String //name 属性抽象的
}class MyImpl : MyInterface2 {override var name: String  runoob //重写属性
} 
函数重写 
实现多个接口时可能会遇到同一个方法继承多个实现的问题。 
interface D {fun foo() {println(D) //已实现}fun bar() //为实现没有方法体是抽象的
}interface E {fun foo() { //已实现println(E)}fun bar() { //已实现println(bar)}
}class F : D {override fun bar() { //重写println(bar)}
}class G : D, E {override fun foo() {superD.foo()superE.foo()}override fun bar() {superE.bar()}
}fun test22() {val g  G()g.foo()g.bar()
//输出D E bar
} 
Kotlin 扩展 
Kotlin 可以对一个类的属性和方法进行扩展且不需要继承或使用 decorator 模式。 
扩展是一种静态行为对被扩展的类代码本身不会造成任何影响。 
扩展函数 
扩展函数可以在已有类中添加新方法不会对原类做修改扩展函数定义形式 
class User(var name: String)fun User.print() {println(用户名 $name)
}fun test23() {val user  User(longsq)user.print()//输出用户名 longsq
} 扩展函数是静态解析的 
扩展函数是静态解析的并不是接受者类型的虚拟成员在调用扩展函数时具体被调用的是那个函数有调用函数的对象表达式决定的而不是动态类型决定。 
open class H
class I : H()fun H.foo()  h //扩展函数 foo
fun I.foo()  d //扩展函数 foofun printFoo(h: H) {println(h.foo()) //类型是 H 类
} 
若扩展函数和成员函数一致则使用该函数时会优先使用成员函数 
class AA {fun foo() {println(成员函数)}
}fun AA.foo() {println(扩展函数)
}fun test24() {val aa  AA()aa.foo()//输出成员函数
} 
扩展一个空对象 
在扩展函数内可以通过 this 来判断接收者是否为 NULL 这样即使接收者为 NULL 也可以调用扩展函数例如 
fun Any?.toString(): String {if (this  null) return null// 空检测之后 “this” 会自动转换为非空类型所以下面的 toString()// 解析为 Any 类的成员函数return toString()
}fun test25() {val t  nullprintln(t.toString())//输出null
} 
伴生对象的扩展 
伴生对象类似 java 中静态方法 
如果一个类定义有一个伴生对象你也可以为伴生对象定义扩展函数和属性。 
伴生对象通过 类名.形式调用伴生对象伴生对象声明的扩展函数通过用类名限定符来调用 
class MyClass {companion object {}//将被成为 companion
}fun MyClass.Companion.foo() {println(伴随对象的扩展函数)
}val MyClass.Companion.no: Intget()  10fun test26() {println(no:${MyClass.no})MyClass.foo()/*** 输出*  no:10伴随对象的扩展函数*/
} 
扩展的作用域 
通常扩展函数或者属性定义在顶级包下 
要使用所定义包之外的一个扩展通过 import 导入扩展的函数名进行使用 
扩展声明为成员 
在一个类内部你可以为另一个类声明扩展 
在这个扩展中有个多个隐含的接收者其中扩展方法定义所在类的实例称为分发接受者而扩展方法的目标类型的实例称为扩展接受者。 
class DD {fun bar() {println(DD bar)}
}class CC {fun baz() {println(CC baz)}fun DD.foo() {bar() //调用 DD.barbaz() // 调用 CC.baz}fun caller(d: DD) {d.foo() //调用扩展函数}
}fun test27() {val dd  DD()val cc  CC()cc.caller(dd)/*输出DD barCC baz*/
} 
假如在调用某一个函数而该函数在分发接受者和扩展接收者均存在则以扩展接收者优先要引用分发接收者的成员你可以使用限定的 this 语法。 
class DD {fun bar() {println(DD bar)}
}class CC {fun bar() {println(CC bar)}fun baz() {println(CC baz)}fun DD.foo() {thisCC.bar() //调用 DD.barbaz() // 调用 CC.baz}fun caller(d: DD) {d.foo() //调用扩展函数}
} 
Kotlin 数据类与密封类 
数据类 
kotlin 可以创建一个只包含数据的类关键字 data 
data class User2(val name: String, val age: Int) 
复制 
复制使用 copy() 函数我们可以使用该函数复制对象并修改部分属性对上文的User2 类 
密封类 
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sun(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()fun eval(expr: Expr): Double  when (expr) {is Const - expr.numberis Sun - eval(expr.e1)  eval(expr.e2)NotANumber - Double.NaN//不再需要 else 子句因为我们已经覆盖了所以的情况
} 
Kotlin 泛型 
泛型即 参数类型 将类型参数化可以用在类接口方法上。 
声明一个泛型类 
class BoxT(t: T) {val value  t
} 
创建类的实例时我们需要指定类型参数 
class BoxT(t: T) {val value  t
}fun test28() {val box  BoxInt(1);val box2  Box(1)
} 
泛型函数 
kotlin 泛型函数的声明与 java 相同类型参数要放在函数名的前面 
class BoxT(t: T) {val value  t
}fun T boxInt(value: T)  Box(value) 
泛型约束 
我们可以使用泛型约束来设定一个给定参数允许使用的类型 
kotlin 中使用对泛型的类型上限进行约束。 
fun T:ComparableT sort(list:ListT){} 
型变 
声明处型变 
声明处的类型变异使用协变修饰符in、out、消费者in、生产者out 
使用 out 使得一个类型参数协变协变类型参数只能用作输出可以作为返回值类型但是无法作为入参的类型 
class Runoobout A(val a: A) {fun foo(): A {return a}
}fun test29() {var strCo  Runoob(a)var anyCo  RunoobAny(b)anyCo  strCoprintln(anyCo.foo())//输出a
} 
in 使得一个类型参数逆变逆变类型参数只能用作输入可以作为入参的类型但是无法作为返回值的类型 
//定义一个支持逆变的类
class Runoob2in A(a: A) {fun foo(a: A) {}
} Kotlin枚举类 
枚举类最基本的用法是实现一个类型安全的枚举。 
枚举常量用逗号分隔每个枚举常量都是一个对象。 
enum class Color {RED,BLACK,BLUE,GREEN,WHITE
} 
枚举初始化 
每一个枚举都是枚举类的实例他们可以被初始化 
enum class Color2(val rgb: Int) {RED(0xFF0000),GREEN(0x00ff00),BLUE(0x0000FF)
} 
enum class Color {RED,BLACK,BLUE,GREEN,WHITE
}fun test30() {val color  Color.BLUEprintln(Color.values())println(Color.valueOf(RED))println(color.name)println(color.ordinal)
} 
可以使用 enumValuesT() 和 enumValueOfT() 函数以泛型方式访问枚举中的常量。 
enum class RGB { RED, GREEN, BLUE }inline fun reified T : EnumT printAllValue() {print(enumValuesT().joinToString { it.name })
}fun test31() {printAllValueRGB()
} 
Kotlin 对象表达式和对象声明 
Kotlin 用对象表达式和对象声明来实现创建一个对某个类做了轻微改动的类的对象且不需要去声明一个新的子类。 
fun test32() {val site  object {val name  菜鸟教程val url  www.runoob.com}println(site.name)println(site.url)
} 
class J{//私有函数所以其返回类型是匿名对象类型private fun foo()  object {val x  x}//共有函数所以其返回类型是 Anyfun publicFoo()  object {val x  x}fun bar(){val x1  foo().x //没有问题//val x2  publicFoo().x //错误未能解析的引用 x}
} 
对象声明 
Kotlin 使用 object 关键字来声明一个对象。 
kotlin 中我们可以方便的通过对象声明来获得一个单例。 
class Site{val name  菜鸟教程object DeskTop{val url  www.runoob.comfun showName(){//println(desk legs $name) //错误不能访问到外部类的方法和变量}}
}fun test33(){val site  Site()//site.DeskTop.url //错误不能通过外部类的实例访问到该对象Site.DeskTop.url //正确
} 
伴生对象 
类内部的对象声明可以用 companion 关键字标记这样它就与外部类关联在一起我们就可以直接通过外部类访问对象的内部元素。 
class MyClass2 {companion object Factory {fun create()  MyClass()}
}fun test34() {val instance  MyClass2.create()//访问到对象的内部元素
} 
对象表达式和对象声明之间的语义差异 
对象表达式是在使用他们的地方立即执行 
对象声明是在第一次被访问到时延时初始化 
伴生对象的初始化是在相应的类被加载时与 java 静态初始化器的语义相匹配 
Kotlin 委托 
委托模式是软件设计模式中的一项基本技巧。在委托模式中有两个对象参与处理同一个请求接受请求的对象将请求委托给另一个对象来处理。 
类委托 
类的委托即一个类中定义的方法实际是调用另一个类的对象的方法实现的。 
//创建接口
interface Base2 {fun print()
}//实现此接口的被委托的类
class Base2Impl(val x: Int) : Base2 {override fun print() {print(x)}
}//通过关键字 by 建立委托类
class Derived2(b: Base2) : Base2 by bfun test35() {val b  Base2Impl(10)Derived2(b).print()//输出10
} 
属性委托 
属性委托指的是一个类的某个属性值不是在类中直接进行定义而是将其托付给一个代理类从而实现对该类的属性统一管理。 
属性委托语法格式 
var/val  属性名: 类型 by 表达式  
定义一个被委托的类 
该类需要包含 getValue() 方法 和 setValue() 方法且参数 thisRef 为惊醒委托的类对象prop为进行委托的属性的对象。 
//定义包含属性委托的类
class Example2 {var p: String by Delegate()
}//委托的类
class Delegate {operator fun getValue(thisRef: Any?, property: KProperty*): String {return $thisRef, 这里委托了 ${property.name}属性}operator fun setValue(thisRef: Any?, property: KProperty*, value: String) {println($thisRef 的 ${property.name} 属性赋值为 $value)}
}fun test36() {val e  Example2()println(e.p) //访问该属性调用 getValue() 函数e.p  Runoob //调用 setValue 函数println(e.p)/*** 输出* com.gxx.testkotlindemo.Example277459877, 这里委托了 p属性com.gxx.testkotlindemo.Example277459877 的 p 属性赋值为 Runoobcom.gxx.testkotlindemo.Example277459877, 这里委托了 p属性*/
} 
标准委托 
Kotlin 的标准库中已经内置了很多工厂方法来实现属性的委托 
延迟属性 Lazy 
lazy() 是一个函数。接受一个 Lambda 表达式作为参数返回一个LazyT 实例的函数。返回的实例可以作为实现延迟属性的委托 
第一次调用 get() 会执已传递给 lazy() 的lambda 表达式并记录结果后续调用 get() 只是返回记录的结果。 
val lazyValue: String by lazy {println(computed!) //第一次调用输出第二次调用不执行Hello
}fun test37() {println(lazyValue) //第一次执行执行两次输出表达式println(lazyValue) //第二次执行只输出返回值/*** 输出* computed!HelloHello*/
} 
可观察属性 Observable 
observable 可以用于实现观察者模式。 
Delegates.observable() 函数接受两个参数第一个是初始值第二个是属性值变化事件的响应器。 
class User3 {var name: String by Delegates.observable(初始值) { property, oldValue, newValue -println(旧值 $oldValue - 新值$newValue)}
}fun test38() {val user  User3()user.name  第一次赋值user.name  第二次赋值/*** 输出* 旧值 初始值 - 新值第一次赋值旧值 第一次赋值 - 新值第二次赋值*/
} 
把属性储存在映射中 
class Site2(val map: MapString, Any?) {val name: String by mapval url: String by map
}fun test39() {val site  Site2(mapOf(name to 菜鸟教程,url to www.runoob.com))//读取映射值println(site.name)println(site.url)/*** 输出* 菜鸟教程www.runoob.com*/
}