《第一行代码》第三版第二章

第二章 探究新语言,快速入门kotlin编程

    • 2.1 kotlin 语言简介
    • 2.2 如何运行kotlin代码
    • 2.3 编程之本:变量和函数
      • 1. 变量
      • 2. 函数
      • 3. 语法糖
    • 2.4 程序的逻辑控制
      • 1. if条件语句
      • 2. when条件语句
      • 3. 循环语句
    • 2.5面向对象编程
      • 1.类与对象
      • 2. 继承与构造函数
        • (1)继承
        • (2)主构造函数
        • (3)次构造函数
      • 3. 接口
      • 4.数据类与单例类
    • 2.6 Lambda编程
      • 1. 集合的创建与遍历
      • 2.集合的函数式API
        • (1)lambda表达式
        • (2)常用的函数API:
      • 3. java函数式API的使用
    • 2.7 空指针检查
      • 1. 可空类型系统
      • 2. 判空辅助工具
        • (1)**?.** : 对象不为空时继续调用相应的方法
        • (2)**!!**: 确信对象不会为空(能不用尽量不要!!)
        • (3)**let**:将原始对象作为参数传递到lambda表达式中
    • 2.8 kotlin中的小魔术
      • 1. 字符串内嵌表达式
      • 2. 函数的参数默认值

2.1 kotlin 语言简介

kotlin继承了java的全部财产后,语法更加简洁,也更加高级,语言更加安全。学习该语言需要有一定的编程基础。(本人课上学的c语言,自己学过java,只学了一点点,不知道算不算是有编程基础哈,先学再说)

2.2 如何运行kotlin代码

三种方法:
1.下载 intellij IDEA(麻烦)
2.在线编程(外国网站,打不开)
3.Android Studio

2.3 编程之本:变量和函数

1. 变量

不可变变量:val(value)
可变变量:var(variable)
kotlin 拥有出色的类型推导机制,可以不声明类型
当然也可以自己声明,这时kotlin不会运行类型推导机制
如: val a = 10
val a:Int = 10

Kotlin完全抛弃了Java中的基本数据类型,全部使用了对象数据类型。在Java中int是 整型变量的关键字,而在Kotlin中Int变成了一个类,它拥有自己的方法和继承结构。
《第一行代码》第三版第二章_第1张图片
优先使用val,后考虑var

2. 函数

在这里插入图片描述
良好的编程习惯:函数名要有一定的意义
《第一行代码》第三版第二章_第2张图片
课本中例子:
fun largerNumber(num1: Int ,num2: Int) = max (num1,num2)

3. 语法糖

见简书:https://www.jianshu.com/p/277ada6d3c3c

2.4 程序的逻辑控制

1. if条件语句

下面是if条件语句在kotlin的简化过程
《第一行代码》第三版第二章_第3张图片
《第一行代码》第三版第二章_第4张图片
《第一行代码》第三版第二章_第5张图片
可见kotlin 有Java的额外功能返回值,并且语法糖的作用不小

2. when条件语句

《第一行代码》第三版第二章_第6张图片
《第一行代码》第三版第二章_第7张图片
《第一行代码》第三版第二章_第8张图片
这里如果else结尾的 when语句会报错

总结:when语句可以代替多个if,有点像switch,并且它还可以进行类型匹配,需要注意的是要以else结尾

3. 循环语句

  1. while循环
    书中没有给出while的讲解,这边给出来,相当于复习以下。
    while (条件表达式) {
    循环语句
    }
    比较简单没有什么好多说的吧
  2. for in 循环
    关键字简介:
    . . (连续的两个点):表示双端闭区间
    until :表示左闭右开区间
    step :跳过某个元素
    downTo :降序区间(双端闭区间)
    《第一行代码》第三版第二章_第9张图片

2.5面向对象编程

备注:半年前学java 的时候就学过了面向对象的编程,到现在对面向对象几个字还是迷迷糊糊,就知道面向对象可以创建类,其他真的就不知道什么了。
在网上找了一个比较能让自己理解的例子区分面向对象和面向过程,如下:

有一天你想吃鱼香肉丝了,怎么办呢?你有两个选择

1、自己买材料,肉,鱼香肉丝调料,蒜苔,胡萝卜等等然后切菜切肉,开炒,盛到盘子里。

2、去饭店,张开嘴:老板!来一份鱼香肉丝!

看出来区别了吗?这就是1是面向过程,2是面向对象。

面向对象有什么优势呢?首先你不需要知道鱼香肉丝是怎么做的,降低了耦合性。如果你突然不想吃鱼香肉丝了,想吃洛阳白菜,对于1你可能不太容易了,还需要重新买菜,买调料什么的。对于2,太容易了,大喊:老板!那个鱼香肉丝换成洛阳白菜吧,提高了可维护性。总的来说就是降低耦合,提高维护性!

面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。

面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。

面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们我们使用的就是面向对象了。

面向过程:

优点:性能比面向对象好,因为类调用时需要实例化,开销比较大,比较消耗资源。
缺点:不易维护、不易复用、不易扩展.

面向对象
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护 .
缺点:性能比面向过程差

作者:猪_队友
链接:https://www.jianshu.com/p/7a5b0043b035
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1.类与对象

类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。
上面是官方的语言,这边举例用通俗得语言解释一下类。
如:我们人类是一个,那么“人”这个类就是抽象的,而真实存在的应该是某个人(具体指明某个人,这个便是是实例化的时候需要做的,实例化后就是对象了)当然这个对象就具有人类所具有的年龄、外貌、能力等属性。

代码如下

package com.example.helloworld

class Person {		//创建人  这个类
    var name = " "			//“人”类的属性
    var age = 0				//“人”类的属性
    fun eat (){				//“人”类的属性
        println(name + "is eating. He is "+ age + "years old.")
    }
}
fun main() {
    val myfriend = Person()		// 这里就是实例化操作 
    myfriend.age = 19			//以下是对对象进行赋值
    myfriend.name = "lihua"
    myfriend.eat()

}

以上如果有理解错误或者解释有误,希望大佬指出,感谢!!!

2. 继承与构造函数

(1)继承

继承:通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。
简单来说就是子类继承父类的特性,扩展父类的功能。
代码如下:《第一行代码》第三版第二章_第10张图片
这里要注意的是:

  1. kotlin在设计之初,默认所有非抽象类都是不可以继承的。(这就是为什么用open)
  2. Peron后有()。

(2)主构造函数

构造函数(主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值):
主构造函数(没有函数体)
如果需要编写一些逻辑需要用到 init
例如:

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

根据继承的特性规定,子类的构造函数必须调用父类的构造函数
我们需要在子类的主调函数上加上父类主调函数的参数,最后传入父类
例如

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

open class  Person(val name :String,val age : Int){
    fun eat (){
        println(name + "is eating. He is "+ age + "years old.")
    }
}

需要注意 子类中定义的name 和 age 没有 val/var 这是避免与父类中的字段造成冲突

(3)次构造函数

次构造函数通过constructor关键字来定义,都必须调用主构造函数(包括间接调用)
代码如下:
《第一行代码》第三版第二章_第11张图片
箭头表示:
第二个次构造函数调用第一个次构造函数(间接调用)
第一个次构造函数调用主构造函数
因此有三种方式对Student类进行实例化,如下:

val student1 = Student()
    val student2 = Student("jack",19)
    val student3 = Student("a123",5,"jack",19)

kotlin中允许只有次构造函数,无主构造函数
此时次构造函数直接调用父类的构造函数 关键字 super,并且子类:后少去(),如下:

class Student : Person{
    constructor(name : String,age: Int):super(name,age){
    }
}

3. 接口

接口有点类似类,但是又有差别,类的抽象是一般化的,而接口就是特殊化
下面直接给出例子:

interface Study {
    fun readBooks()
    fun doHomework()
}

class Student(name: String,age: Int) : Person(name,age),Study{
    override fun readBooks() {
        println(name + "is reading book")
    }
    override fun doHomework() {
        println(name + "is doing homework")
    }
}

多态(面向接口编程) 如下:

fun main() {
    val student = Student("jack",19)
    doStudy(student)
    
}
fun doStudy(study: Study){
    study.readBooks()
    study.readBooks()
}

这里的Study是个类型(个人理解为能做学习这件事的类型)
所以Student这个类就是能做学习这个事的
所以就是 实例化一个 student 将这个实例传进doStudy()中
kotlin中允许接口中定义的函数进行默认实现。
可见修饰符
《第一行代码》第三版第二章_第12张图片

4.数据类与单例类

《第一行代码》第三版第二章_第13张图片
《第一行代码》第三版第二章_第14张图片
小节总结:这节让我重新学习了面向对象编程,之前Java的面向对象编程没有学的很扎实,基本也忘记关了,这节重新算是重新认识了一下。不过感觉学完还是没有很深的认识,大概只是了解了名词和代码实现。学习的过程也花了挺长的时间,大概一节都花了一个下午。。。

2.6 Lambda编程

1. 集合的创建与遍历

List Set Map 集合
List如下:

val list1 = listOf<String>("apple","banana","orange","pear","grape")
    for(fruit1 in list1)
        println(fruit1)
    val list2 = mutableListOf<String>("apple","banana","orange","pear","grape")
    list2.add("watermelon")
    for(fruit2 in list2 )
        println(fruit2)

详细请看:
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/array-list-of.html
Set集合 和List 集合相似,set无法保证有序

Map集合如下:

/* val map = HashMap()
    map["apple"] = 1
    map["banana"] = 2
    map["orange"] = 3
    map["peat"] = 4
    map["grape"] = 5 */
    val map = mapOf("apple" to  1,"banana" to 2,"orange" to 3)
    for ((fruit,number) in map){	//这里fruit和number的用法注意一下
        println("fruit is "+ fruit +",number is " + number)

2.集合的函数式API

(1)lambda表达式

《第一行代码》第三版第二章_第15张图片
举例:
《第一行代码》第三版第二章_第16张图片
这里用map函数映射,然后一个元素进去lambda 出来一个新的元素 最后map合并成一个新的集合
《第一行代码》第三版第二章_第17张图片

(2)常用的函数API:

map
filter:需要注意的是,在filter与其他函数共同使用时,先用filter那样可以提高效率

val list = listOf<String>("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
    val newlist = list.filter { it.length <= 5 }
        .map{it.toUpperCase()}
    for (fruit in newlist) {
        println(fruit)
    }

any:任何一个满足条件
all:所有都满足条件
如下:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
    val any = list.any{it.length <= 5}
    val all = list.all { it.length <= 5 }
    println("any is "+any +",all is "+all)

3. java函数式API的使用

在这里插入图片描述

/*
    java 版本创建并执行一个子线程
    new Thread(new Runnable(){
    @Override
    public void run(){
        System.out.println("Thread is running");
     }
     }).start()
     kotlin 未简化版
     Thread (Object : Runnable {
        override fun run(){
            println("Thread is running")
            }
      }).strat()
    */
    Thread(Runnable {
        println("Thread is running")
    }).start()

这一小节看的有点迷糊,但是我觉得这些东西应该多接触了就不会,所以在这边直接给出kotlin调用java方法时使用API的语法

2.7 空指针检查

1. 可空类型系统

《第一行代码》第三版第二章_第18张图片
《第一行代码》第三版第二章_第19张图片

fun main() {
    doStudy(null)
}

fun doStudy(study: Study?){

    if(study != null) {  //这里需要对study进行判断 否则会出现 readBoooks() 和 doHomework()
        study.readBooks()
        study.readBooks()
    }
}

2. 判空辅助工具

(1)?. : 对象不为空时继续调用相应的方法

fun main() {
    doStudy(null)
}

fun doStudy(study: Study?){

        study?.readBooks()
        study?.readBooks()

}

学习一个 ?: 常用的方法: 表示左边不空则返回左边,否则返回右边的表达式结果

val c = a ?: b

(2)!!: 确信对象不会为空(能不用尽量不要!!)

如下:

    var content : String? = "hello"
fun main() {
    if (content != null){
        printupperCase()
    }
        
}
fun printupperCase(){
    val upperCase = content!!.toUpperCase()
    println(upperCase)
}

(3)let:将原始对象作为参数传递到lambda表达式中

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

结合lambda表达式的参数列表中只有一个参数时,可以不用声明参数名化简

fun doStudy(study: Study?) {
    study?.let {
        it.readBooks()
        it.doHomework()
    }
}

而且 let 可以处理全局变量,而if不行!!

2.8 kotlin中的小魔术

1. 字符串内嵌表达式

${ } : 当表达式中只有一个变量的时候,还可以省去大括号。

fun main() {
    val brand = "samsung"
    val price = 1299.99
    println("Cellphone(brand=$brand,price=$price)")

2. 函数的参数默认值

《第一行代码》第三版第二章_第20张图片
kotlin还有一个神奇的机制:键值对的方式传参数,如下:

fun printParams(num: Int = 100, str: String) {
    println("num is $num , str is $str")
}
fun main() {
   printParams(str = "world")
}

这种方式会大程度的替代次构造函数的作用!!

章节总结:这一章节大概花了十个小时的时间,不能说学得很好,也没有很差,面对对象那块确实刚刚学起来有点困难(学java学过,但是没有怎么学)。

以下是一些个人在学习过程中的经验或者说犯的错误

  1. Android studio 的字体太小,容易把标点打错或者看错。(如冒号打成分号)点击解决
  2. 这是我遇到的一个错误,当时 } 这个在很下面,我集中在main函数上就没有去考虑下面的,然后点击了一下划绿线的地方就跳到了这个错误的地方。
    《第一行代码》第三版第二章_第21张图片
    以上是部分内容是个人理解,如有错误请大佬在评论区指出,感谢!!!

你可能感兴趣的:(第一行源代码)