为什么学习Kotlin?
Kotlin是Google规定的官方Android开发语言
Kotlin是JetBrains开发的,google把Kotlin作为Android的官方语言。
学习路线
第一种:Android官网:
https://developer.android.google.cn/kotlin/add-kotlin
第二种:https://www.jetbrains.com/
首页的Learning Tools 选择 Kotlin for Education
文档
Kotlin语言参考文档:
https://www.kotlincn.net/docs/reference/
http://shouce.jb51.net/kotlin/
kotlin基础课目录
Kotlin基础语法 – simple01
Kotlin比较与数组 – simple02
Kotlin条件控制 – simple03
Kotlin循环与标签 – simple04
Kotlin类与对象 – simple05
kotlin基础
可以选中Kotlin写的类文件,然后点击Tools -> Kotlin -> show Kotlin Bytecode 查看对应的字节码:
然后点击Decompile可以查看反编译后的java源码:
通过查看反编译后的java源码可以知道kotlin一些语法的原理。
simple01 Kotlin 基础语法
1.Var 与 Val
可变变量定义:var 关键字
var <标识符> : <类型> = <初始化值>
不可变变量定义:val 关键字,只能赋值一次的变量(有一点点类似Java中final修饰的变量)
val <标识符> : <类型> = <初始化值>
// TODO Var 与 Val
fun main() {
// 可变变量定义:var 关键字
// var <标识符> : <类型> = <初始化值>
// 不可变变量定义:val 关键字,只能赋值一次的变量(有一点点类似Java中final修饰的变量)
// val <标识符> : <类型> = <初始化值>
// 可以修改的
var name: String = "Derry"
name = "张三"
name = "李四"
var info1 = "AAAA" // 类型推导,kotlin可以根据后面变量的值推导出变量的类型,因此不用写 var info1: String = "AAAA"
var info2 = 'A' // 类型推导 Char
var info3:Int = 99 // 类型推导 Int
// 不可以修改的
val age: Int = 99
// age = "" 报错
// 静态语言,即在编译期就决定了info4变量是String类型,再次赋值为Int型的88值就会报错
var info4 = "LISI" // info4==String类型
// info4 = 88 // 但是js可以这么做,因为js是态解释语言
}
class Test {
// 可以改,可以读 get set
//var info1 : String = "A"
// 只能读, 只有 get
val info2 : String = "B"
}
2.函数
package simple01.s02
// TODO 函数 方法
// void == :Unit
fun main(): Unit {
println(add(1, 1))
lenMethod(1, 2, 3, 4, 5, 6, 7)
// lambda表达式函数
val addMethod : (Int, Int) -> Int = {number1, number2 -> number1 + number2}
val r= addMethod(9, 9)
println(r)
}
// 返回类型Int
fun add(number1: Int, number2: Int): Int {
return number1 + number2
}
// 返回类型 == 类型推导 Int
fun add2(number1: Int, number2: Int) = number1 + number2
// 返回类型 == 类型推导 String
fun add3(number1: Int, number2: Int) = "AAA"
// 可变参数 (可变长 参数函数)
fun lenMethod(vararg value: Int) {
for (i in value) {
println(i)
}
}
3.字符串模板
package simple01.s03
// TODO 字符串模板
fun main() {
// $ 表示一个变量名或者变量值
// $varName 表示变量值
// ${varName.fun()} 表示变量的方法返回值
val name = "张三"
val age = 28
val sex = 'M'
val info = "ABCDEFG"
println("name:$name, age:$age, sex:$sex info:$info")
// --- 使用三个换行,则自己不用关心 \n 换行 ,不用自己调整
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)
// 需求:显示 $99999.99
val price = """
${'$'}99999.99
""".trimIndent()
println(price)
}
4.NULL检查机制
package simple01.s04
// TODO NULL检查机制
fun main() {
// Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,
// 有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?
var info: String? = null
// println(info?.length) // 第一种补救:? 如果info是null就不执行 .length,不为null才执行
// println(info!!.length) // 第2种补救: !! 我自己负责确保info不会为null == (不管null或者非null都执行,若info为null则抛出异常) == Java
// 所以用 !! 的时候要确保info不可能为null
/*
if (info != null) // 第3种补救: == Java
println(info.length)
*/
// println(testMethod("AAAAA"))
// 刚那个提问的呢?
// ?: 如果你一定要输出null 就让你 “你很牛逼”
println(info?.length ?: "你很牛逼")
}
// : Int? 即 允许返回null
fun testMethod(name: String) : Int? {
if (name == "zs") {
return 99999
}
return null
}
5.区间
package simple01.s05
// TODO 区间
fun main() {
// 1 到 9
for (i in 1..9) {
// println(i)
}
// 不会输出
for (i in 9..1) {
// println(i)
}
// 大 到 小
for (i in 9 downTo 1) {
// println(i)
}
// 用区间做判断
val value = 88
if (value in 1..100) {
// println("包了 1 到 100")
}
// 步长指定
for (i in 1..20 step 2) {
// 1 3 5 7 ...
// println(i)
}
// 排除 最后元素
for (i in 1 until 10) {
println(i)
}
}
simple02 比较与数组
1.比较两个值
package simple02.s01
// TODO 比较两个值
fun main() {
val name1: String = "张三"
val name2: String = "张三"
// --- 比较值本身
// == 等价 Java的equals
println(name1.equals(name2))
println(name1 == name2)
// --- 比较对象地址
val test1:Int? = 10000
val test2:Int? = 10000
println(test1 === test2) // false
}
2.数组
package simple02.s02
// TODO 数组
fun main() {
// 第一种形式
val numbers = arrayOf(1, 2, 3, 4, 5, 6, 7, 8)
// println(numbers[0])
// println(numbers[7])
for (number in numbers) {
// println(number)
}
// 第二种形式 value=0
// 0 + 200 = 200
// 1 + 200 = 201
val numbers2 = Array(10, {value: Int -> (value + 200) })
for (value in numbers2) {
println(value)
}
// 定义一个变量 value Int类型
// value=0 + 200
// {value: Int -> (value + 200) }
}
simple03 条件与控制
1.条件
2.when运用
package simple03
// TODO 条件
fun main() {
val number1: Int = 9999999
val number2: Int = 8888888
// 表达式 比 大小 最大值
val maxValue = if (number1 > number2) number1 else number2
// println(maxValue)
val max: Int = if (number1 > number2) {
println("number1是最大的哦")
// TODO
// ....... 省略 200行代码
number1
} else {
println("number2是最大的哦")
// TODO
// ....... 省略 200行代码
number2
}
// println(max)
// 使用区间做判断
val x = 80
val y = 29
if (x in 1..10 && y in 1..50) {
// println("x y 轴 符合")
} else {
// println("x y 轴 不符合")
}
println()
/* val number = 5
when(number) {
1 -> println("一")
2 -> println("二")
3 -> println("三")
4 -> println("四")
5 -> println("五")
else -> println("其他")
}*/
/*val number = 745
when(number) {
in 1..100 -> println("1..100")
in 200..500 -> println("200..500")
else -> println("其他")
}*/
// Object == Any ?
// val str : String = ""
val number = 3
val result = when (number) {
1 -> {
println("很开心")
// 很多很多的逻辑.. 省略 200行代码
// ...
// TODO ....
"今天是星期一"
99
}
2 -> {
println("很开心")
// 很多很多的逻辑.. 省略 200行代码
// ...
// TODO ....
"今天是星期二"
88
}
3 -> {
println("很开心")
// 很多很多的逻辑.. 省略 200行代码
// ...
// TODO ....
"今天是星期三"
true
100
}
else -> 99
}
// println(result)
when (8) {
1, 2, 3, 4, 5, 6, 7 -> println("满足")
else -> println("不满足")
}
}
simple04 循环与标签
1.for循环操作
2.自带标签与系统标签
package simple04.s01
// TODO 循环 与 标签
fun main() {
// TODO 自定义标
tttt@ for (i in 1..20) {
for (j in 1..20) {
println("i:$i, j:$j")
if (i == 5) {
// break // j循环给break
break@tttt // i循环给break,即结束掉外面的循环,类似goto
}
}
}
// TODO 循环
var items = listOf<String>("李四", "张三", "王五")
for (item in items) {
println(item)
}
//forEach 是一个闭包,默认有一个参数it
items.forEach {
println(it)
}
//也可以自定义参数
items.forEach { a ->
println(a)
}
//打印下标,类似迭代器
for (index in items.indices) {
println("下标:$index, 对应的值:${items[index]}")
}
}
// 自带的标签@Derry
class Derry {
val I = "AAAA"
fun show() {
println(I)
println(this.I)
println(this@Derry.I)
}
}
simple05 类与对象
1.父类子类 与 构造函数等
package simple05.s01
// TODO 类与对象
fun main() {
val person = Person() // 次构造
val person2 = Person(6465) // 主构造
Person(464, "Derry") // 次构造
Person(464, 'M') // 次构造
}
package simple05.s01
// public final class Person 默认就是这样的,不能被继承,可以加open就可以被人家继承了
open class Person(id: Int) // 主构造
{
// 次构造
constructor(id: Int, name: String) : this(id) {
}
// 次构造
constructor(id: Int, sex: Char) : this(id) {
}
// 次构造
constructor() : this(787) {
}
}
package simple05.s01
class Student(id: Int) :
// Person() // 次构造
Person(id) // 主构造了
{
// 在Kotlin中, 全部都是没有默认值的,因此没有赋予初始值会报错
//var area : String
// 在Java中, 成员有默认值,但是方法内部没有默认值
//var name : String? = null // 可以使用String?类型,并赋予初始值null
// 也可以使用 lateinit 关键字来修饰变量,懒加载,这样就不需要在声明变量的时候赋予初始值了
// lateinit修饰的变量必须赋值,如果没有赋值就使用,则会报错
lateinit var name : String
var age: Int = 0
}
2.接口和抽象类
package simple05.s02
// 默认是 public final class Person ,是不能被人家继承的。
// 如果加上abstract,abstract有open的特征, 相当于open
abstract class Person : Callback , Callback2 {
abstract fun getLayoutID() : Int
abstract fun initView()
}
package simple05.s02
class Student : Person() {
override fun getLayoutID(): Int = 888
override fun initView() { }
override fun callbackMethod(): Boolean = false
}
3.data 与 object
data:
package simple05.s03
/**
* 数据类 相当于 Java实体Bean
*
* 用了data修饰后,就不能加{}了
*/
// 用了data修饰后,会自动生成get方法 set方法 构造方法 equals方法 hashCode方法 toString方法 copy方法
data class User(val id: Int, val name: String, val sex: Char)// 如果User不会再修改,则参数可以使用val
object:
package simple05.s03
// object 只实例一次,相当于 单例。可以看到,类的图标颜色是黄色的
// object修饰后不用加构造函数
object MyEngine {
fun m() {
println("M run " + this)
}
fun show() {
println("我就只有一个实例")
}
}
package simple05.s03
/**
* 普通的类
*/
class MyEngineNormal() {
fun m() {
println("M run " + this)
}
fun show() {
println("show()")
}
}
测试:
package simple05.s03
// TODO data数据类 ,object单例
fun main() {
//data数据类
val user = User(99, "lisi", 'M')
val(myID, myName, mySex) = user.copy()//copy()方法的使用
println("myID:$myID, myName:$myName, mySex:$mySex")
// _ 代表不接收
val(_, myName2, _) = user.copy()
println("myName2:$myName2")
//object单例
// --- 调用5此m()方法,相当于new了五次
MyEngineNormal().m();
MyEngineNormal().m();
MyEngineNormal().m();
MyEngineNormal().m();
MyEngineNormal().m();
//而MyEngine只相当于new了1次,因为MyEngine是object修饰的,是单例
MyEngine.m()
MyEngine.m()
MyEngine.m()
MyEngine.m()
MyEngine.m()
}
4.自己写单例
package simple05.s04
// TODO Kotlin 单例模式1:饿汉式的单例模式
class NetManager {
// 用object修饰,只有一个Holder实例
object Holder {
val instance = NetManager()
}
// 看不到 static,可以用companion(即派生操作)
companion object {
// companion里面的方法全部都是 相当于 Java static
fun getInstance() : NetManager = Holder.instance
}
fun show(name: String) {
println("show:$name");
}
}
// 客户端
fun main() {
val net = NetManager.getInstance()
net.show("kt Derry1")
}
package simple05.s04
// TODO kt 单例模式2:懒加载的单例模式
class NetManager2 {
companion object {
private var instance: NetManager2? = null//kotlin里面全部都没有默认值,必须赋予一个初始值
// 返回值是NetManager2?:允许你返回null
fun getInstance(): NetManager2? {
if (instance == null) {
instance = NetManager2()
}
// 如果是null,也返回去了
return instance
// 第二种补救: 我来确保 instance 肯定不为null
// return instance!!
}
/* // 返回值NetManager2?:允许你返回null
fun getInstance(): NetManager2 {
if (instance == null) {
instance = NetManager2()
}
// 第二种补救: 我来确保 instance 肯定不为null
return instance!!
}*/
}
fun show(name: String) {
println("show:$name");
}
}
fun main() {
//如果getInstance()返回值是NetManager2? 即允许返回值是null, 则客户端使用时需要做判断
val netManager = NetManager2.getInstance()
// 如果 netManager == null ,则不执行 .show("AAA")
netManager?.show("AAA")
}
5.内部类与嵌套类
package simple05.s04
/**
* 内部类和嵌套类的使用
*/
class InnerClass {
val I = "AAAA"
// 这个不是一个内部类,所有拿不到外部类的成员
// 这个是嵌套类,嵌套类的作用:可以在类的里面再写一个类,但是这个类和外部类不交互
class Sub {
fun show() {
println()
}
//可以写很多嵌套类
class A {
class B {
class C {
}
}
}
}
//inner修饰的这个才是内部类
inner class Sub2 {
fun show() {
println(I)
}
}
}
fun main() {
//嵌套函数
fun a() {
fun b() {
fun c() {
fun d() {
}
}
}
}
}