1,基础语法
1.1 可变变量与不可变变量
可以多次赋值的变量是可变变量,用关键字var表示:
var <标识符> : <类型> = <初始化值> 注意,在kotlin中成员变量不会赋默认值,不像java一样,必须手动添加默认值。
var name : String ="yuanzhen"
name ="yuanzhen1"
var age : Int =20
age =30
println("name:$name,age:$age") 
输出:
name:yuanzhen1,age:30 
只能赋值一次的变量,是不可变变量,用关键字val表示,类似于java里面的final:
val <标识符> : <类型> = <初始化值> 注意,在kotlin中成员变量不会赋默认值,不像java一样,必须手动添加默认值。

1.2类型推导
kotlin可以根据传入的值,自动推导出变量类型:
var name ="yuanzhen"  //类型推导
name ="yuanzhen1"
var age =20  //类型推导
age =30 
1.3函数 方法
kotlin中的Unit相当于java中的void ,如果函数的返回值为Unit,可以不用写返回值
kotlin中使用fun关键字定义函数
定义一个有参数和返回值的函数:
fun test(name1:String ,name2:String):String{
    return name1+name2
} 
调用:
println(test("yuan","zhen"))
//输出 yuanzhen 
也可以根据类型推导,直接写成:
fun test(name1:String ,name2:String) =name1+name2 
可变参数用关键字vararg表示:
fun lenMethod(vararg value: Int) {
    for (i in value) {
        println(i)
    }
} 
调用:
lenMethod(1, 2, 3, 4, 5, 6, 7) 
1.4字符串
在kotlin中,$表示一个变量名或者变量值,$name 表示变量值,如果变量值有多个,可以写为:${name1+name2}
var name ="yuanzhen1"  //类型推导
var name1 ="yuanzhen"
println("${name+name1}") 
输出:yuanzhen1yuanzhen
换行:""" """ 自己不用关心换行:
val infoMesage = """
    AAAAAAAAAAA
    BBBBBBBBBBB
    CCCCCCCCCCC
    DDDDDDDDDDD
    EEEEEEEEEEE
"""  // 前置空格
println(infoMesage)
val infoMesage2 = """
    AAAAAAAAAAA
    BBBBBBBBBBB
    CCCCCCCCCCC
    DDDDDDDDDDD
    EEEEEEEEEEE
""".trimIndent()  // 没空格
println(infoMesage2)
val infoMesage3 = """
    ?AAAAAAAAAAA
    ?BBBBBBBBBBB
    ?CCCCCCCCCCC
    ?DDDDDDDDDDD
    ?EEEEEEEEEEE
""".trimMargin("?")  // 没空格 控制?
println(infoMesage3) 
输出:
    AAAAAAAAAAA
    BBBBBBBBBBB
    CCCCCCCCCCC
    DDDDDDDDDDD
    EEEEEEEEEEE
AAAAAAAAAAA
BBBBBBBBBBB
CCCCCCCCCCC
DDDDDDDDDDD
EEEEEEEEEEE
AAAAAAAAAAA
BBBBBBBBBBB
CCCCCCCCCCC
DDDDDDDDDDD
EEEEEEEEEEE 
1.5 null检查机制
在kotlin中,如果你这么定义一个变量,一定会报错的

因为这是kotlin特有的机制,不允许直接赋空值。那么要怎么做呢?
var age:Int?=null 
加个?的意思就相当于 我发出了一个广播,告诉所有人这个值可能是空的,必须要有处理措施。
第一种处理措施:
var age:Int?=null
val i = age?.and(2)
println("$i") 
输出:null
age?.and(2)的意思就是如果age是null,那就不执行?后面的内容了
第二种处理措施:
var age:Int?=null
age!!.and(2) 
!!的意思就是我不管,我就强行执行and方法,出了事我负责。
第三种处理措施:
就跟java一样,自己判断处理
var age:Int?=null
if(age !=null){
    age.and(2)
} 
1.6 区间
区间用..来表示
// 1 到 9
for (i in 1..9) {
    println(i)
} 
输出 1 2 3 4 5 6 7 8 9
那如果这样写呢?
for (i in 9..1) {
    println(i)
} 
注意:这样是不会输出的,因为没有9到1这种写法,那如果非要输出9到1呢?
for (i in 9 downTo 1) {
    println(i)
} 
要用downTo
还可以指定步长:
for (i in 1..20 step 2) {
   println(i)
} 
输出:1 3 5 7 9 11 13 15 17 19 每隔2输出一个值
排除最后一个元素:
for (i in 1 until 10) {
    println(i)
} 
输出:1 2 3 4 5 6 7 8 9
2, 比较与数组
2.1比较
在java中比较两个字符串,用equls来比较,但是在kotlin中,用==来比较字符串的值
val name1: String = "张三"
val name2: String = "张三"
println(name1 == name2) 
比较对象地址用===表示
// ---  比较对象地址
val test1:Int? =  10000
val test2:Int? =  10000
println(test1 === test2) 
输出false
2.2 数组
在java中数组有三种创建方式:
int[] array  = {1,2,3};
int[] array1 = new int[3];
int[] array2 = new int[]{7,8,9}; 
在kotlin中 数组有两种方式:
第一种:
val numbers = arrayOf(1, 2, 3, 4, 5, 6, 7, 8) 
第二种:
val numbers2 = Array(10,  {value: Int -> (value + 200) })
for (value in numbers2) {
    println(value)
} 
输出:
200
 201
 202
 203
 204
 205
 206
 207
 208
 209
为什么会这样呢? 因为value的默认值是0,之后会依次加一。
3,条件控制
比较大小值,可以这样写:
val number1: Int = 99
val number2: Int = 88
// 表达式 比 大小 最大值
val maxValue = if (number1 > number2) number1 else number2
println(maxValue) 
输出99
如果要执行多行代码,还可以这样写:
val max: Int = if (number1 > number2) {
    println("number1是最大的")
    number1
} else {
    println("number2是最大的")
    number2
} 
注意:返回值不需要加return关键字
when相当于java中的switch case,只不过用法更加灵活
用于某个值:
val number5 = 5
when(number5) {
    1 -> println("一")
    2 -> println("二")
    3 -> println("三")
    4 -> println("四")
    5 -> println("五")
    else -> println("其他")
} 
用于区间:
val number = 700
when(number) {
    in 1..100 -> println("1..100")
    in 200..500 -> println("200..500")
    else -> println("其他")
} 
用于执行多行代码 并且有返回值:
val number = 3
val result = when (number) {
    1 -> {
        println("很开心")
        "今天是星期一"
        99
    }
    2 -> {
        println("很开心")
        "今天是星期二"
        88
    }
    3 -> {
        println("很开心")
        "今天是星期三"
        true
        100
    }
    else -> 99
} 
4,循环与标签
4.1标签
自定义标签:在kotlin中,我们可以自定义一个标签,用来控制程序的执行流程等
yuanzhen@ for (i in 1..20) {
    for (j in 1..20) {
        println("i:$i, j:$j")
        if (i == 5) {
            // break // j循环 给break
            break@yuanzhen // i循环 给break
        }
    }
} 
一个类中自带的标签:
class Yuan {
    val I = "aa"
    fun show() {
        println(I)
        println(this.I)
        println(this@Yuan.I)
    }
} 
4.2循环
在kotlin中,要遍历一个list,通常有三种方式:
var items  = listOf<String>("aaa", "bbb", "ccc") 
方式一:
for (item in items) {
    println(item)
} 
方式二:
items.forEach {
    println(it)
} 
方式三:
for (index in items.indices) {
    println("下标:$index,  对应的值:${items[index]}")
} 
5,类与对象
5.1类的创建
在kotlin中,创建一个类,如果前面不写修饰符,默认就是public final
// 默认就是public final
class Empty 
这样是不能被继承的,要想被继承,就必须加上open
open class Person{} 
5.2构造函数
在java中,会有一个默认的构造函数,并且可以重载无数个构造函数。
但是在kotlin中,它会有一个默认的主构造函数,其余的都是次构造。
上面的Person类,相当于有一个默认的主构造:
open class Person() // 主构造
{
} 
那如果我们要给主构造增加一个参数呢?
open class Person(id: Int) // 主构造
{
} 
那如果还要增加好几个次构造呢?
open class Person(id: Int) // 主构造
{
    // 次构造
    constructor(id: Int, name: String) : this(id) {
    }
    // 次构造
    constructor(id: Int, sex: Char) : this(id) {
    }
    // 次构造
    constructor() : this(222) {
    }
} 
次构造必须继承主构造,同时把参数传给主构造
在使用时,可以这么用:
val person = Person() // 次构造
val person2 = Person(23456) // 主构造
Person(234, "yy") // 次构造
Person(234, 'M') // 次构造 
5.3类的继承
继承父类用:表示
class Student(id: Int) : Person(id) // 主构造
{
    // 再Kotlin 全部都是没有默认值的
    // 再Java 成员有默认值,但是方法内部没有默认值
    // lateinit 懒加载  没有赋值 就不能使用,否则报错
    lateinit var name : String
    var age: Int = 0
} 
5.4接口
在kotlin中,接口和抽象类默认都是open的
interface Callback {
    fun callbackMethod() : Boolean
} 
interface Callback2 {
    fun callbackMethod() : Boolean
} 
abstract class Person : Callback , Callback2 {
    abstract fun getLayoutID() : Int
    abstract fun initView()
} 
class Student : Person() {
    override fun getLayoutID(): Int = 888
    override fun initView() { }
    override fun callbackMethod(): Boolean  = false
} 
与java差别不大
5.5data数据类
数据类是kotlin中独有的,在java中,我们要写数据类,通常会手写很多属性和方法等。
在kotlin中,我们只需要用数据类定义属性就可以,不用关心get,set等方法,内部会自动帮我们生成。
// 会自动生成get set 构造 equals hashCode toString copy
data class User(val id: Int, val name: String, val sex: Char) 
val user = User(99, "lisi", 'M')
//copy 函数
val(myID, myName, mySex) = user.copy()
println("myID:$myID, myName:$myName, mySex:$mySex") 
5.6单例
在kotlin中,object只实例一次,相当于单例
object MyEngine {
    fun m() {
        println("M run")
    }
    fun show() {
        println("我就只有一个实例")
    }
} 
companion :意思是同伴对象。相当于java的static.
下面来看一下kotlin中的单例模式怎么写:
方式一:
class NetManager {
    // 只有一个实例
    object Holder {
        val instance = NetManager()
    }
    // 看不到 static  可以 派生操作
    companion object {
        // 全部都是  相当于 Java static
        fun getInstance() : NetManager = Holder.instance
    }
    fun show(name: String) {
        println("show:$name");
    }
} 
方式二:
class NetManager2 {
    companion object {
        private var instance: NetManager2? = null
        // 返回值:允许你返回null
        fun getInstance(): NetManager2? {
            if (instance == null) {
                instance = NetManager2()
            }
            // 如果是null,也返回回去了
            return instance
            // 第二种补救: 我来负责 instance 肯定不为null
            // return instance!!
        }
    }
    fun show(name: String) {
        println("show:$name");
    }
} 
5.7嵌套类
嵌套类,就是在类的内部又写了一个类,但是它不是内部类,拿不到外部类的成员。
class Sub {
    fun show() {
        println()
    }
    class A {
        class B {
            class C {
            }
        }
    }
} 
5.8内部类
在kotlin中,内部类用关键字inner来表示。
class Sub {
    fun show() {
        println()
    }
    class A {
        class B {
            class C {
            }
        }
    }
   }
    // 这个才是内部类
    inner class Sub2 {
        fun show() {
            println(I)
        }
    }
} 
                

















