安卓开发学习---kotlin版---笔记(一)

Hello word

前言:上次学习安卓,学了Java开发,简单的搭了几个安卓界面。这次要学习Kotlin语言,然后开发安卓,趁着还年轻,学点新东西,坚持~
未来的你会感谢现在努力的你~

安卓开发学习---kotlin版---笔记(一)_第1张图片

主要学习资料:

  • 《第一行代码Android 第三版》
  • 菜鸟教程
  • android官网-kotlin
  • Kotlin 官方文档 中文版
  • 2018年黑马安卓开发视频教程
  • 幕课网课件

那么,开始吧~

开始-Kotlin语言-安卓开发学习

首先是搭建环境,在一通操作过后,在android studio上成功安装行了kotlin
经典的:hello word

安卓开发学习---kotlin版---笔记(一)_第2张图片

eclipse环境搭建结果:


参数

又是一个绕不开的话题
kotlin中
使用val修饰的变量,是不可变的(value)
使用var修饰的变量,是可变的(variable 可变的)

  • tips: 优先使用val来声明一个变量,而当val没有办法满足你的需求时再使用var

小数类型的,默认是Double
var a = 3.1415f/3.1415F表示Float类型
小数点6位以内,用Float类型
小数点大于6位,用Double类型

for循环

  • kotlin也有swift中的开区间、闭区间的概念
    四种类型:[],(),[),(]

注意,所谓 “全开区间” 或者是 “左开右闭” 的区间,可以用其他两种方式代替

	var nums = 1..10
    for (num in nums){
        print("$num, ")
    }
    println()
    var nums2 = 1 until 10
    for (num in nums2){
        print("$num, ")
    }

运行结果:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1, 2, 3, 4, 5, 6, 7, 8, 9,

  • step n隔几个,打印1个
    for (num in 1..20 step 2){
        print("$num, ")
    }

运行结果:1, 3, 5, 7, 9, 11, 13, 15, 17, 19,

  • reversed()翻转打印
    var nums2 = 1 until 10
    for (num in nums2.reversed()){
        print("$num, ")
    }

运行结果:9, 8, 7, 6, 5, 4, 3, 2, 1,

数据容器

容器是用于存放数据的载体。容器分为数组、集合

  • 使用arrayOf创建数组
var array: Array<Any> = arrayOf("1", "2", 2, 3.11)

kotlin中的Any类型,等价于其他开发语言中的object类型

  • 使用arrayOfNulls创建数组
    创建一个指定大小的、所有元素都为空的数组,但必须指定集合中的元素类型
    var array2 = arrayOfNulls(5)
	var array2 = arrayOfNulls<String>(2)
    array2[0] = "333"

    for (temp in array2){
        println(temp)
    }

运行结果:
333
null

  • 动态创建数组
    用接受数组大小,以及一个方法参数的Array构造方法,用作参数的方法能够返回给定索引的每个元素初始值
    //数组的大小:4
    //遍历数组,i。取出每一个i,做i*i的操作,结果放入数组
    var array3 = Array(4){i -> (i*i)}
    array3.forEach { println(it) }
根据不同类型,创建特定类型的数组
  • 指定类型
	//指定个数
    var array4 = IntArray(2)
    array4[0] = 1
    array4[1] = 99
    array4.forEach { println(it) }
  • 指定类型,指定个数,且每个元素一样
    //创建一个长度为5的数组,里面每个元素都是100
    var array5 = IntArray(5){100}
    array5.forEach { println(it) }
  • 指定类型,指定个数,且每个元素可按规则自定义
    var array6 = IntArray(5){it*2}
    array6.forEach { println(it) }
数组的几种for-in循环遍历
    var array6 = IntArray(5){it*2}
    //最简单的
    for (item in array6){
        println(item)
    }
    
    //使用indices,取index
    for(index in array6.indices){
        println("array6[${index}] = ${array6[index]}")
    }

    //使用withIndex,取出index和item
    for((index, item) in array6.withIndex()){
        println("array6[${index}] = ${item}")
    }
  • 数组创建的时候,需要指定个数,而且创建完成后,不能更改数字个数(不能添加、删除元素),只能查询、更改元素值

这明显是个不可变数组,难度没有可变数组吗?还是说可变数组使用集合表示?

Kotlin集合

可变集合的大小可以动态改变

  • List:是一个有序集合,元素可重复
  • Set:是一组无重复元素的集合(无序)
  • Map:是一组键值对(字典)
可变集合、不可变集合

安卓开发学习---kotlin版---笔记(一)_第3张图片

在可变的列表中,有两个方法,推荐使用带mutable的,字如其意

例子:创建一个可变集合,做增、删操作
    var array = mutableListOf<String>()
    //增加元素
    array.add("123")
    array.add("333")
    //在index的位置,增加元素
    array.add(1, "2")

    var array2 = mutableListOf<String>()
    array2.add("1")
    array2.add("3")

    //增加一个数组里面的内容
    array.addAll(array2)
    array.forEach { println(it) }

    //根据下标index移除元素
    array.removeAt(0)
    //根据value移除元素
    array.remove("333")
    array.forEach { println(it) }

listOf()创建集合的时候,必须指定元素类型、必须指定初始化数据

例子:创建一个不可变集合,做增、删操作

使用listOf创建一个list
使用witIndex()获取index的值,然后使用(x, y)两个参数接收

	fun main(args: Array<String>){
    var array = listOf<String>("1", "2", "4", "9")
    for ((index, item) in array.withIndex()){
        println("$index "+"$item")
    }

运行结果:
0 1
1 2
2 4
3 9

例子:创建一个map
//导入TreeMap包
import java.util.TreeMap

fun main(args: Array<String>){
	//创建一个map
    var map2 = TreeMap<String, String>()
    //赋值
    map2["good"] = "好"
    map2["bad"] = "坏"
    map2["study"] = "学习"
    println(map2["bad"])
}

readLine()

readLine():获取键盘输入的字,获取后是String?类型的


函数

函数的格式:

kotlin:

func 函数名(参数名: 参数类型): 返回值类型{
	函数体
}

oc:

- (返回值类型)函数名(参数类型: 参数名) {
	函数体
}

只是组合方式不一样
函数的四要素:函数名、参数、返回值类型、函数体都有

函数的简略写法:

fun sum(a: Int, b: Int): Int{
    return a+b
}
//如果函数体里面只有一条语句,而且该语句有返回值,则可以去掉{},并省略return,直接使用=:
fun sum2(a: Int, b: Int): Int = a+b

在kotlin中,函数和参数(变量)一样,都是一等公民
那个,也可以将函数表达式赋值给一个变量:

	///等号右边,称为:函数表达式
    var i = {a: Int, b: Int -> a+b}
    println(i(3, 8))

还有另外一种写法:

	//var j:后面,表面是一种类型,j是一个函数类型,两个入参,一个出参
	//=后面,是一个函数表达式
    var j:(Int, Int)->Int = {x, y -> x+y }
    println(j(1, 8))

也就是,函数也可以充当函数里面的参数,或者返回值

函数的分类

函数通过声明位置的不同,分为:

  • 普通类的方法(对象方法)
  • 静态类的方法(类方法)
  • companion object伴生类的方法

companion:同伴,伴侣

普通方法:
class Person {
    fun test(){
        println("普通方法")
    }
}

调用的时候,先创建对象,才能调用
Person().test()

静态类方法

使用objec创建的类,称为静态类
不需要构建对象,可以通过类名,直接访问静态方法

object NumUtil {
    fun test(){
        println("这是一个静态方法")
    }
}

调用:NumUtil.test()

伴生类方法

如何在一个普通类里面,直接通过类调用方法呢?
可以将方法放在companion object{}里面即可

class Person {
    companion object{
        fun test2(){
            println("这是一个伴生类方法")
        }
    }
}

调用Person.test2()

方法的参数

  • 默认参数
  • 具名参数
  • 可变数量的参数
默认参数

方法参数可以有默认值,当省略相应的参数时使用默认值

fun main(args: Array<String>){
    read(1,2)
    read(start = 2)
}

fun read(offset: Int = 0, start: Int){
    println("offset=${offset}, start=${start}")
}

运行结果:
offset=1, start=2
offset=0, start=2

offset: Int = 0就是默认值0
当不写默认值的时候,要指定后面的参数start
而这种在调用函数的时候,指定参数名的方法,就是具名参数

具名参数,指定具体名称的参数

举个例子:默认参数与具名参数
val PI = 3.14f

fun main(args: Array<String>){
    //要写3.14f,3.0f,而不是3.14,3
    var temp = circleArea(3.14f, 3.0f)
    //调用的时候,明确写出radius=的方式,就是具名参数
    var temp2 = circleArea(radius = 3.0f)
    println(temp)
    println(temp2)
}

//圆的面积
//默认Pi的值是PI
//通过在类型的后面添加 = 符号来设置参数的默认值。
fun circleArea(Pi: Float = PI, radius: Float): Float{
    return Pi*radius*2
}
  • 如果最后一个参数是方法,那么,它既可以作为具名参数在括号内传入,也可以在括号外传入
举个例子
fun main(args: Array<String>){
    //作为具名参数,在括号内
    read1(1,2, action = {
        //最后一句可以省略return
        "123"
    })

    //放在括号外
    read1(start = 3){
        "321"
    }
}

//最后一个参数是方法
//action:参数名
//()->String:没有参数,有返回值(String)的函数类型
fun read1(offset: Int = 0, start: Int, action: ()->String){
    //函数(),代表执行函数
    var temp = action()
    println("offset=${offset}, start=${start}, action=${temp}")
}
可变数量的参数Vararg

vararg:可变参数

方法的参数(通常是最后一个),可以使用vararg修饰标记:

fun main(args: Array<String>){
    varargFun(1, 100)
    varargFun(1, 3, 3,4,8)
}

//使用vararg修饰
fun varargFun(a: Int, vararg v:Int){
    //v参数是一个数组
    println(v.forEach { println(it) })
}
  • 一个函数,最多只能有一个可变参数
  • 如果可变参数不是最后一个,那么可变参数后面的所有参数,都要用具名参数传值

Lambda表达式

Lambda表达式理解为一种语法糖
Lambda表达式里面有一个it

it不是关键字
在高阶方法中,如果Lambda表达式只有一个参数,那么可以使用it来使用此参数

异常捕获try-catch

举个:计算器

fun main(args: Array<String>){
    println("请输入第一个数字:")
    var a = readLine()

    while (a == null || a?.count() == 0){
        println("不能输入空值,请重新输入数字:")
        a = readLine()
    }

    println("请输入第二个数字:")
    var b = readLine()
    while (b == null || b?.count()==0){
        println("不能输入空值,请重新输入数字:")
        b = readLine()
    }
    try {
        var num1 = a!!.toInt()
        var num2 = b!!.toInt()
        var result = sum(num1, num2)
        println("$num1 + $num2 = $result")
    }catch (error: java.lang.Exception){
        println(error)
    }
}

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

递归

举个例子:计算n的阶层

5的阶层 = 5 * 4 * 3 * 2 * 1 = 120

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

fun jieCeng(a: Int):Int{
    //结束条件
    if (a == 1) return 1
    //递归计算
    return a * jieCeng(a-1)
}
尾递归计算
fun main(args: Array<String>){
    var result = 0
    println(add(100, result))
}

tailrec fun add(a: Int, result: Int):Int{
    println("计算机第${a}次计算, result=${result}")
    //结束条件
    if (a == 0) return 1
    //递归计算
    return add(a-1, result + a)
}

继承

  • 如果想继承某个父类,则父类class前需要加open,允许被继承
  • 如果想重写父类的某个方法,则子类在同名方法前加overrid,且父类在方法前加open,允许被重写

接口和抽象类

  • 接口是事物的能力,接口用的时候:接口名即可
  • 抽象类是事物的本质,抽象类用的时候:抽象类+()

使abstract定义的类,被称为抽象类,里面的方法不需要实现

代理和委托

A委托B去做某事情
B代理A去做某事情

使用by 类名A(),就可以实现类名A里面的方法

	open class Father: IWashBowl by Son(){
    /**
    override fun wash() {
        println("我是爸爸,洗完一次10元")
    }
     * */
	}

//或者这样调用
open class Father: IWashBowl by Son(){
    override fun wash() {
        println("我是爸爸,我收了妈妈的10元")
        Son().wash()
        println("我是爸爸,我不洗碗,但是赚了9元")
    }
}

单例

创建类的时候,不使用class修饰,而且使用object修饰,则只有一份

印章类sealed

sealed:封闭的、密封的

  • sealed class更在意类型
  • 枚举更在意数据
//跟enum类似,只有指定有限的类
sealed class Son {
    //记得加()
    class XXL(): Son()
    class XXM(): Son()

    fun sayHello(){
        println("hello")
    }
}

fun main(args: Array<String>){
    //记得加(),才是对象
    var son1:Son = Son.XXL()
    var son2:Son = Son.XXM()
    var son3:Son = Son.XXM()

    var house = listOf<Son>(son1, son2, son3)
    for (v in house){
        if(v is Son.XXM){
            v.sayHello()
        }
    }
}

函数式编程

fun main(args: Array<String>){
    var names = listOf<String>("tom", "locy", "jack")
    //forEach函数
    names.forEach(action = haha)
    //闭包,匿名函数
    names.forEach{
        a -> println(a)
    }
    //闭包
    names.forEach{
        //默认参数it
        println(it)
    }
}

//函数作为参数,前面使用var 参数名 =
//后面的函数名去掉
var haha = fun (name: String):Unit{
    println(name)
}

Kotlin高阶函数

一个函数,被用作参数或者返回值,则称为高阶函数

maxBy/minBy

找出数组array,里面age最大的item
array.maxBy{a.age}
找出数组array,里面height最小的item
array.minBy{a.height}

返回的是item对象

var item: Object = array.maxBy{it.age}

filter

  • 过滤找到特定条件的对象集合
    好几个条件并列执行:
var newArray = array.filter{
	(it.age>18) and (it.height>168) and (it.age<25)
}

map

  • 把原数组某个属性,映射成新的集合
    比如:把人群中的名字列出来,放入新的集合中
var newArray = oldArray.map{
	"${it.name} : ${it.age}"
}

结果:{name1: 18, name2: 30, name3: 19}

any

  • 是否有满足某个条件的对象
    返回的是一个boolean值
var temp: Boolean = array.any{
	it.age == 18
}

count

  • 统计符合满足条件对象的个数
var count: Int = array.count{
	it.age<18
}

find

  • 查找符合条件的对象,并返回第一个
var item: Object = array.finc{
	it.address=="北京"
}

groupBy

  • 按照特征,把对象分为不同的组
var result: Array = array.groupBy{
	it.address
}

按照地址,把原来的数组,分别组成新的数组

DSL 领域特定语言

  • 扩展函数
  • 中缀表达式
    函数使用infix修饰后,.的操作,可以换成空格的操作

泛型

在java中,常见的泛型有:泛型类、泛型接口、泛型方法、泛型属性
在kotlin中,常见的泛型有:泛型接口/类、泛型字段、泛型方法、泛型约束、泛型中的out与in

泛型接口/类

举个例子:使用泛型定义一个接口
fun main(args: Array<String>){
    DrinkApple().drink("喝苹果汁")
}

//接口,泛型
interface Drink<T>{
    //不需要函数体
    fun drink(t: T)
}

//定义一个类DrinkApple,实现Drink接口
class DrinkApple: Drink<String>{
    //使用override重写
    override fun drink(t: String) {
        println(t)
    }
}
泛型类

fun main(args: Array<String>){
    BlueColor("蓝色").printColor()
    BlueColor("红色").printColor2()
}

//使用abstract修饰一个类,类名为Color
abstract class Color<T>(var t: T){
    //如果不实现函数,则也加abstract
    abstract fun printColor()
    //或者不加abstract,直接实现函数
    fun printColor2(){
        println("printColor2")
    }
}

class BlueColor(var color: String): Color<String>(color){
    override fun printColor() {
        println("${color}")
    }
}

泛型参数
fun main(args: Array<String>){
    var box1 = Box<String>("123")
    println("${box1.value}")
}

///(Box)是一个整体,且不能省略(省略的话,后面的T不识别)
class Box<T>(t: T){
    var value = t
}

泛型方法

这个。。。。,方法也是泛型?

类型参数要放在方法名的前面

fun main(args: Array<String>){
    //Kotlin中双冒号操作符:表示把一个方法当做一个参数,传递到另一个方法中进行使用,通俗的来讲就是引用一个方法。
    fromJson("{}", String::class.java)
}

//在函数名前加
fun <T> fromJson(json: String, tClass: Class<T>): T?{
    var t: T? = tClass.newInstance()
    return t
}

泛型约束

就是,对泛型进行约束,约束泛型是哪种类型的子类

//规定,泛型必须是JSONObject类型,或者其子类类型
fun <T: JSONObject> fromJson(json: String, tClass: Class<T>): T?{
    var t: T? = tClass.newInstance()
    return t
}

当泛型前后不一致的时候,需要借助out/in


扩展Extensions

扩展的好处:提高编码效率,减少代码量

扩展某个类一个新的功能,而无需继承该类

扩展一个方法:

fun main(args: Array<String>){
    Jump().test()
    Jump().test2()
}

//正常创建一个类
class Jump{
    fun test(){
        println("test")
    }
}

//扩展一个类的方法,只需要在类后面加.即可
fun Jump.test2(){
    println("test2")
}

Jump类,里面多了一个test2()方法

使用场景:当引用的第三方框架,想增加新的方法,就可以使用扩展

扩展属性
fun main(args: Array<String>){
    var android = "android"
    println("${android.lastChar}")
}

//普通定义变量 var a: Char
//get() = this.get(length - 1)左边是get放,右边是实现
val String.lastChar:Char get() = this.get(length - 1)

Kotlin中常用的扩展

提供的扩展函数:

  • let
  • run
  • apply
let

let: 作用域区域、避免判空

fun main(args: Array<String>){
    testLet("sss")
    testLet(null)
}

//String?代表可能为空
fun testLet(str: String?){
    //当str为空的话,不执行后面的函数
    str?.let {
        var str2 = "android"
        println(str2 + it)
    }
    //let函数外面,不能访问str2
//    str2
}
run

run函数,只接收一个lambda函数参数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式
在run函数中,可以直接访问实例的公有属性和方法

fun main(args: Array<String>){
    //调用函数,入参是Jump()
    var temp = testRun(Jump())
    println(temp)
}

//创建一个类
class Jump{
    var a: Int = 10
    fun test(){
    }
}

//函数
fun testRun(jump: Jump): String{
    jump.run {
        jump.test()
        //直接访问方法
        test()

        println(jump.a)
        //直接访问属性
        println(a)

        //最后一行,被作为返回值
        return "1111"
    }
}
apply

调用某个对象的apply函数,在函数范围内,可以调用该对象的任意方法,并返回该对象

作业:做一个计算器

package com.example.learnKotlin

fun main(args: Array<String>){
    while (true){
        println("====请输入你的表达式====")
        var inputString: String? = readln()
        try {
            inputString?.let {
                calculate(inputString)
                println("====是否还继续?(y/n)====")

                var inputString2: String? = readln()
                inputString2?.let {
                    if (it.equals("n")){
                        System.exit(-1)
                    }
                }

            }
        }catch (ex: java.lang.Exception){
            ex.printStackTrace()
        }
    }
}

fun calculate(inputString: String){
    if(inputString.contains("+")){
        //trim()去掉空格
        //split()分割
        var nums = inputString.trim().split("+")
        var result = nums[0].toFloat() + nums[1].toFloat()
        println("${nums[0]}+${nums[1]}=${result}")

    }else if(inputString.contains("-")){
        var nums = inputString.trim().split("-")
        var result = nums[0].toFloat() - nums[1].toFloat()
        println("${nums[0]}-${nums[1]}=${result}")
    }else if(inputString.contains("*")){
        var nums = inputString.trim().split("*")
        var result = nums[0].toFloat() * nums[1].toFloat()
        println("${nums[0]}*${nums[1]}=${result}")
    }else if(inputString.contains("/")){
        var nums = inputString.trim().split("/")
        var result = nums[0].toFloat() / nums[1].toFloat()
        println("${nums[0]}/${nums[1]}=${result}")
    }else{
        println("输入错误")
    }
}

测试数据:

请输入你的表达式
8=0
输入错误
是否还继续?(y/n)
y
请输入你的表达式
8 * 8
8 * 8=64.0
是否还继续?(y/n)
请输入你的表达式
9-000
9-000=9.0

你可能感兴趣的:(安卓学习,android,学习,kotlin)