900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 第一行代码读书笔记(Chapter2 探究新语言 快速入门Kotlin编程)

第一行代码读书笔记(Chapter2 探究新语言 快速入门Kotlin编程)

时间:2023-09-09 13:38:20

相关推荐

第一行代码读书笔记(Chapter2 探究新语言 快速入门Kotlin编程)

准确来说,Java是解释性语言,Kotlin能被编译为class文件,再在虚拟机中运行

Kotlin几乎杜绝了空指针异常

运行Kotlin代码:IDEA创建Kotlin项目;在线运行kotlin代码;Android Studio创建一个main()函数

fun main() {println("Hello, world!!!")}

2.3.1变量

Kotlin中定义一个变量,只允许valvar进行声明。

valvalue的简写)声明不可变的变量,对应Java中的final变量,不可二次赋值(地址)

varvariable的简写)用来声明一个可变的变量,对应Java中的非final变量。

Kotlin拥有出色的类型推导机制

var a=10 //整型var b="hello" //字符串

代码结尾不加分号

val a: Int = 10 //显示声明变量a为Int类

Kotlin中完全摒弃基本数据类型,全部使用对象数据类型

全部使用对象数据类型

全部使用对象数据类型

全部使用对象数据类型

Number是Kotlin内置抽象类,是Int、Long、Float、Double的父类

Java与Kotlin数据类型对照表

永远优先使用val来声明一个变量,而当val没有办法满足你的需求时再使用var。这样设计出来的程序会更加健壮,也更加符合高质量的编码规范

2.3.2 函数

函数==方法

main()函数是程序的入口函数

//入口函数fun main() {println("Hello, world!!!")}//自定义函数fun methodName(param1: Int,param2: Int):Int{return 0}

fun:定义函数的关键字

参数格式:参数名称:类型 paramName:Int

返回值类型:在参数括号后,不写则默认为void

import kotlin.math.maxfun main() {val a = 30val b = 43val value = largerNumber(a,b)println("larger number is "+value)}​fun largerNumber(num1: Int,num2: Int):Int{return max(num1,num2)}

语法糖:若函数中只有一行代码,Kotlin允许直接将该行代码写在函数定义尾部,并用等号连接。

= 表达了 return

//= 表达 returnfun largerNumber(num1:Int,num2:Int):Int = max(num1,num2)

继续简化,让Kotlin自动推导返回类型

fun largerNumber(num1:Int,num2:Int) = max(num1,num2)

2.4 程序逻辑控制

顺序语句

条件语句:if 和 when

循环语句:

2.4.1if条件语句

与Java相同的用法;略

if有返回值:

//每个条件的最后一行代码作为返回值fun largerNumber(num1:Int,num2:Int):Int{val value = if(num1>num2){num1}else{num2}return value}//简化,直接返回fun largerNumber(num1:Int,num2:Int):Int{return if(num1>num2){num1}else{num2}}//仅一行代码,继续简化fun largerNumber(num1:Int,num2:Int) = if(num1>num2){num1}else{num2}

继续简化

fun largerNumber(num1:Int,num2:Int)=if(num1>num2) num1 else num2

2.4.2when条件语句

when是为解决switch的痛点,并增加许多强大的新特性

when也有返回值

//精准匹配when(param){​匹配值 -> { 执行逻辑 }"Tom" -> 10 //当参数值为Tom时返回10}​//类型匹配 is相当于Java中instanceOf关键字when(param){is Int -> {}is Double -> {}else -> {}}//简化 前fun getScore(name:String)=if(name == "Tom"){86} else if(name =="Jim"){77}else if(name == "Jack"){95}else if(name == "Lily"){100}else{0}//使用when简化fun getScore(name:String) = when(name){"Tom" -> 86"Jim" -> 77"Jack" -> 95"Lily" -> 100else -> 0}fun checkNumber(num:Number){//类型匹配when(num){is Int -> println("number is Int")is Double -> println("number is Double")else -> println("number not support")}}//无参数的when语句fun getScore(name:String) = when{//将条件表达式写在匹配值的位置,可对参数做一定的操作name.startsWith("Tom") -> 86name == "Jim" -> 77name == "Jack" -> 95name == "Lily" -> 100else -> 0}

2.4.3循环语句

while循环与Java一样

for循环不同

for-in循环

声明一个闭区间

val range = 0..10 //创建[0,10]的区间 闭区间

fun main() {//使用 for-in 循环遍历区间for(i in 0..10){println(i)}}

开区间

val range = 0 until 10 //创建[0,10)的区间

step:设置步长,每次加几

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

..until创建升序区间

降序区间downTo

fun main(){for(i in 10 downTo 1){println(i)}}

2.5.1 类与对象

创建类Person:

class Person{var name = ""var age = ""fun eat(){println(name + " is eating. He is " + age +"years old.")}}

实例化类:与Java的区别,去掉了new

val p = Person() //表示调用了该类的构造函数fun main(){val p = Person()p.name = "Jack" // 为Person的实例化对象赋值p.age = 19p.eat()// 调用方法}

2.5.2 继承与构造函数

Effective Java这本书中明确提到,如果一个类不是专门为继承而设计的,那么就应该主动将它加上final声明,禁止它可以被继承。

继承

新建Student类

class Student{var sno = ""var grade = 0}

要让Student类继承Person类,需要做两件事:

1.使Person类可以被继承

在kotlin中任何一个非抽象类默认不可被继承,相当于Java中给类加final

open关键字:在class之前加

open class Person{}

2.继承:使用:

class Student : Person() {var sno = ""var grade = 0}

()表示调用了构造函数

Kotlin中构造函数

主构造函数 和 次构造函数

主构造函数

默认都有一个不带参数的主构造函数,可显示指明参数,它没有函数体,直接定义在类名后

//sno与grade字段在被初始化后不可变,故直接设置为val//主构造函数 将字段都放入其中 class Student(val sno: String, val grade:Int) : Person(){}

在实例化以上类时,必须传入构造函数中所有的参数

val student = Student("wu",59)

构造函数中的参数创建实例时传入的,不需要重新赋值,因此我们可以将参数全部声明为val

主构造函数无函数体,若想在主构造函数中编写一些逻辑,可写在init结构体中

class Student(val sno: String, val grade: Int) : Person(){init{println("sno is "+sno)println("grade is "+grade)}}

继承规定:子类 中的构造函数必须调用 父类 中的构造函数

如何体现调用了呢?括号()

改造Person为有参构造函数

open class Person(val name: String, val age: Int){...}

改造Student类

// 将父类的name,age属性作为参数,但不需要指定var或valclass Student(val sno: String, val grade: Int,name: String,age: Int) : Person(name,age){init{println("sno is "+sno)println("grade is "+grade)}}

不能再将父类中的字段声明为val,因为在父类已经指定了。

次构造函数

一个类只能有一个主构造函数,但可以有多个次构造函数

次构造函数与主构造函数的区别:有函数体

Kotlin规定:一个类有主又有次,所有次必须调用主(包括间接调用:调用调用主的次构造函数)

次构造函数通过constructor关键词定义

这里定义两个次构造函数:

第一个接收name和age参数,通过this关键字调用主构造函数,并为主构造函数赋值

第二个不接收任何参数,通过this调用另一个次构造函数

class Student( val sno: String,val grade: Int, name: String,age: Int) :Person(name,age){constructor(name:String, age:Int):this("",0,name,age){}constructor(): this("",0){}}

无主构造函数,仅有次构造函数,委派隐式发生,并执行块

class Person(val pets: MutableList<Pet>=mutableListOf())​class Pet{constructor(owner: Person){owner.pets.add(this)}}

若类具有主构造函数,则次构造函数,则次构造函数中必须调用主构造,间接或直接

使用this()来调用主构造

即使类没有主构造函数,委派仍然隐式发生,并且仍然执行初始值设定项块:

class Constructors {init {println("Init block")}​constructor(i: Int) {println("Constructor $i")}}

且这个生成的 主构造函数的可见性 是公开的

若不希望它是公共的,就需要声明可见性

class DontCreateMe private constructor(){ }

2.5.3接口

单继承,多实现

继承与实现都使用 : 来实现

接口后无()

实现接口就必须实现接口中所有抽象方法

支持多态

支持多个默认方法

函数的可见性修饰符

Kotlin中有4种,定义在fun前

public

所有类可见,在Kotlin中属于默认项

private

与Java一致,只在本类中可以访问

protected

在Kotlin中表示对当前类和子类可见

internal

只对同一模块内的类可见

2.5.4数据类(实体类POJO)与单例类

数据类

在Java中一个实体类中,需要有构造方法,get/set方法,hashCode(),toString等

在Kotlin中只需一行代码 data

data class Cellphone(val brand: String, val price: Double)

只需在类之前加data,Kotlin会根据主构造函数中参数自动生成equals(),hashCode(),toString()等方法,减少开发工作量

在使用==比较两个对象时,会自动调用equals(),data根据参数来比较,若参数相同则true

单例类

在Kotlin中,只需将class关键字改为object关键字即可

object Singleton{}object Singleton{fun singletonTest(){println("singletonTest is called.")}}

//调用方式Singleton.singletonTest()

2.6 Lambda编程

2.6.1 集合的创建与遍历

List,Set

ArrayList,LinkedList

HashSet

HashMap

val list = ArrayList<String>()list.add("Apple")list.add("Banana")list.add("Orange")list.add("Pear")

//简化写,相当于Java中Arrays.asList();val list = listOf("Apple","Banana","Orange","Pear")

List集合

//遍历集合fun main(){val list = listOf("Apple","Banana","Orange","Pear")for(fruit in list){println(fruit)}}

listOf()与Java中一样,也是不可变的集合,不能添加、修改或删除

可变集合

使用mutableListOf()

fun main(){val list = mutableListOf("Apple","Banana","Orange","Pear")list.add("Watermelon")for(fruit in list){println(fruit)}}

Set集合

自动去重

val set = setOf("Apple","Banana","Orange","Pear")​for(fruit in set){println(fruit)}

Map集合

HashMap

//类似Java写法val map = HashMap<String,Int>()map.put("Apple" ,1)map.put("Banana", 2)

Kotlin中不建议使用put()和get()方法对Map进行加和读

推荐使用数组下标语法结构

map["Apple"] = 1

读取

val number = map["Apple"]

简便写法:mapOf(),mutableMapOf()

val map = mapOf("Apple" to 1,"Banana" to 2,"Orange" to 3,"Pear" to 4)

to不是关键字,而是infix函数

遍历Map集合

fun main(){val map = mapOf("Apple" to 1,"Banana" to 2,"Orange" to 3,"Pear" to 4)for((fruit, number) in map){println("fruit is " + fruit +", number is "+ number)}}

2.6.2 集合的函数式API

maxBy

1.找出水果集合中单词最长的水果

val list = listOf("Apple","Banana","Orange","Pear")val maxLengthFruit = list.maxBy { it.length }println("max length fruit is " + maxLengthFruit)

不建议在Lambda表达式中编写太长的代码

Lambda表达式的语法结构:

{ 参数名1: 参数类型, 参数名2: 参数类型 ->函数体 }

参数列表结尾的->,表示函数体的开始

函数体中可以写任意行代码,最后一行代码会自动作为 返回值

由繁入简

maxBy:普通函数,接收一个Lambda类型的参数,

在遍历时将遍历的值作为参数传递给Lambda表达式。

工作原理:以传入的内容为条件并最大化的要求来遍历集合,

传入length则条件自然就是单词长度

//原始写法:val list = listOf("Apple","Banana","Orange","Pear")//规则 { 参数名1: 参数类型 ->函数体 }val lambda = { fruit: String -> fruit.length }val maxLengthFruit = list.maxBy(lambda)

不用lambda参数

val maxLengthFruit = list.maxBy({fruit: String -> fruit.length})

Kotlin规定:当Lambda参数是函数最后一个参数时,可将Lambda表达式移到函数括号外

val maxLengthFruit = list.maxBy() { fruit: String -> fruit.length }

根据类型推导,进一步简化

val maxLengthFruit = list.maxBy{ fruit -> fruit.length }

当Lambda表达式的参数列表只有一个参数,不必声明参数名,用it关键字代替

val maxLengthFruit = list.maxBy { it.length }

map

//将所有水果名变大写val newList = list.map{ it.toUpperCase() }

filter

过滤集合中的数据,可结合其他函数一起使用

//先保留5个字母以内的水果,留下的单词 变大写

//先过滤再变大写效率高,反过来就低一点

val newList = list.filter{ it.length <= 5 }

.map{ it.toUpperCase() }

any,all

any:是否存在

all:是否所有都

2.6.3Java函数式API的使用

如果在Kotlin中调用Java方法,该方法接收了一个Java单抽象方法接口参数,就能使用函数式API

单抽象方法接口:Runnable接口

new Thread(new Runnable(){@Overridepublic void run(){System.out.println("Thread is running");}}).start();

翻译为kotlin

//创建匿名类用object关键字Thread(object : Runnable{override fun run(){println("Thread is running")}}).start()

使用Lambda表达式规则化简

Thread(Runnable{println("Thread is running")}).start()

若参数列表仅有一个Java单抽象方法接口参数

Thread({println("Thread is running")}).start()

Lambda表达式是方法最后一个参数,移到方法括号外,

唯一一个参数,省略括号Thread()

Thread{println("Thread is running")}.start()

button.setOnClickListener{}

2.7 空指针检查

Kotlin默认参数和变量都不可以为空,若为空,编译出错

若业务逻辑需要个空,则需要可为空的类型系统

2.7.1 可为空的类型系统

在类名后加上问号

Int?表示可为空整型

String?表示可为空字符串

却依然编译不通过,

还需要处理掉空指针异常

判空

fun doStudy(study: Study?){//这样就是处理了if(study != null){study.xx()study.xx()}}

2.7.2 判空辅助工具

?.操作符

当对象不为空时正常调用,为空什么都不做

if(a!=null){a.doSomething()}​等价于||||a?.doSomething()

fun doStudy(study: Study?){//这样就是处理了study?.xx()study?.xx()​}

?:操作符

左右都接收一个表达式,左不为空则返回左边,否则返回右边

val c = a ?: b

val c = if(a != null){a} else {b}

操作符混用

// text可能为空 不为空调用length。否则啥也不做 fun getTextLength(text: String?) = text?.length ?: 0//不为空返回length。否则返回0

若已经进行了非空判断,仍编译失败,如在方法外判断非空,而方法内不知道,编译不通过

非空断言

在对象后面加!!

表示我确信这个对象不会为空,不需要你再来做空指针检查了。

var content: String? = "hello"​fun main(){if(content != null){printUpperCase()}}​fun printUpperCase(){val upperCase = content!!.uppercase() // !! 尽量少用println(upperCase)}

let函数

函数式API编程接口,会将调用对象作为参数传递到表达式中

obj.let{obj2 ->//编写具体业务逻辑}

obj与obj2实际上是同一个对象

实例:

var study: Study?=null​fun doStudy(study: Study?){//有点啰嗦,两次判断同一个对象是否为空study?.xx()study?.xx()​}

fun doStudy(study: Study?){study?.let{stu ->stu.XX()stu.XX()}}

//继续简化fun doStudy(study: Study?){study?.let{it.xx()it.xx()}}

2.8 Kotlin中的小魔术

2.8.1 字符串内嵌表达式

将表达式写在字符串中

${}

仅有一个变量时,大括号省略

val brand = "Samsung"val price = 1299.99​println("Cellphone(brand="+brand+", price="+price+")")​//化简println("Cellphone(brand=$brand, price=$price)")

2.8.2函数的参数默认值

通过给函数的参数设定默认值,一定程度上替代次构造函数的功能

//设置了默认值,实例化时可传可不传fun printParams(num: Int, str: String = "hello"){println("num is $num, str is $str")}​fun main(){printParams(123)}

// 存在顺序问题fun printParams(num: Int = 100, str: String){println("num is $num, str is $str")}​//通过键值对传参fun main(){printParams(str="hello")printParams(str="hello",num=123)}

2.9 小结

变量、函数、逻辑控制语句、面向对象编程、Lambda编程、空指针检查机制...

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。