Kotlin入门笔记(适合有JAVA最基本基础的)

本笔记摘抄自《第一行代码》第三版 郭霖著
注意:Kotlin的语句最后没有分号

修饰符

  • JAVA
    • public(所有类可见)
    • private (当前类可见)
    • protected (当前类 子类 同一包路径下的类可见)
    • default(默认就是这个 同一包路径下的类可见)
  • Kotlin
    • public(所有类可见 默认是这个)
    • private (当前类可见)
    • protected (当前类 子类)
    • internal(只对一个模块中的类可见)

1.变量

  • 变量声明:val 不可变变量 ; var 可变变量
    /因为开发过程中JAVA代码总有人不在不可变的变量前加final,所以Kotlin为了修复这个问题,强制让你必须声明可不可变
    小tips:永远先用val,后期逻辑需要改变变量的时候再回去改成var
    /

  • Kotlin可以像Python那样推导变量的类型,但是不是总是有效的,推荐显示赋值声明。例如: val a: Int = 10

  • 类型种类有 Int Long Short Float Double Boolean Char Byte

2.函数

  • main()函数是程序的入口函数,程序运行开始,从main()开始执行

  • 定义:fun MethodName(param1: Int, param2: Int) : Int { return 0 } /除了用冒号后显示返回值 其它的和JAVA几乎一致/

  • 例如: fun largerNumber(num1: Int, num2: Int) : Int { reuturn max(num1,num2) }/看不懂建议重修C语言 另外在AndroidStudio中尽量使用自动导包而不是手动导包 手导很容易错/

3.逻辑语句

  • 条件语句
    • if
示例代码

/*和JAVA的一样*/
fun largerNumber(num1: Int, num2: Int){
  var value = 0
  if(num1 > num2){
      value = num1
  }else{
      value = num2
  }
  return value
}

/*和JAVA不一样的 Kotlin的If语句可以有返回值*/
fun largerNumber(num1: Int, num2: Int){
  val value = if (num1 > num2){
                  num1 }
              else{
                  num2 }
  return value
}

你甚至可以 fun largerNumber(num1: Int, num2: Int) = if(num1 > num2){num1} else {num2}
  • when (类似于switch语句)
    为了解决JAVA中switch老是要break的问题出现了when
    • 格式是 匹配值 -> {逻辑代码} 此外 when可以进行类型匹配
示例代码
fun getScore(name: String) = when(name){
  "yi" -> 80
  "er" -> 90
  "san" -> 100
}

类型匹配

fun checkNumber(num: Number){
//Number是Kotlin的一个数字抽象类
  when(num){
    is Int -> println("Int")
    is Double -> println("Double")
  //...多的就不打了
  }
}

还有一种特殊的不带参数的用法
fun getScore(name: String) = when{
  name == "Tom" -> 86
  name == "Jim" -> 77
  else -> 0
}

3.循环语句

  • while语句
    和其它语言的一毛一样 不说了

  • for语句

  • 闭区间关键字".." for(i in 0..10){println(i)} //[0,10]进行遍历

  • 左闭右开 "until" 跨越"step", for(i in 0 until 10 step 2) {prinln(i)} //打印结果为 0 2 4 6 8

  • 降序区间 downTo for(i in 10 downTo 1) {println(i)} //是[10,1]遍历 打印结果为 10 9 8 7 6 5 4 3 2 1

  • 遍历集合和数组

4.类和对象


  • 和JAVA相比,取消了new关键字,因为你的意图很可能只是实例化一个对象
示例代码
class Me{
  var name = "Baixianliu"
  var age = 0
}

fun main(){
  val me = Me()
}

5.继承和构造

  • 继承
    • Kotlin中默认所有的非抽象类都是不可继承的,所以如果要在类的定义前面加入关键字 open 表明类是可以继承的
    • Kotlin中的继承和CPP的关键字一样,用的是":"关键字 例如 class Student : Me()
  • 构造
    • 任何面向对象语言都有构造函数,Kotlin中的构造函数分为主构造函数和次构造函数
    • 主构造函数特点:没有函数体 直接定义在类名后面 没有参数,也可以显示指明参数
示例
class Student(val sno: String, val grade: Int) : Person(){
//那么没有函数体 如果想在主构造函数写一些逻辑代码 就得用Init语句
  init{
    println("sno is" + sno)
    pritnln("grade is" + grade)
  }
}
    • JAVA中规定,子类必须调用父类的构造函数,Kotlin也一样,但是主构造函数没有函数体 怎么调用呢? 注意:在init中调用是不好的做法
    • Kotlin中继承父类名后的括号就是用来指定调用父类的哪一个构造函数的。
  • 次构造函数(几乎用不到)
    • 一个类有一个主构造函数,又可以有多个次构造函数。(因为没用 我就不写了)

6.接口

  • 接口是实现多态的重要组成部分 Kotlin和JAVA一样,都是单继承结构的语言,最多只能继承一个父类,但是可以实现任意多个接口。
  • 先在接口中定义一系列的抽象行为,然后由具体的类去实现,JAVA中继承是extends,实现用implement,而Kotlin都是用冒号":"
示例代码
interface Study{
  fun readBooks()
  fun doHomework()
}

class Student(name:String, age: Int) : Person(name, age), Study{
  override fun readBooks(){println(name + " is reading ")
  override fun doHomework(){println(name + " do homework ")
}
  • 另外JAVA JDK1.8后允许在接口内进行函数的编写,Kotlin也一样,例如在上面的代码中 fun doHomework(){ "do homework default"},这样之后,即使类没有实现doHomework也不会报错

7.数据类与单类

  • 数据类
    • 数据类用于将服务器端或数据库中的数据映射到内存中 为代码逻辑提供数据模型的支持
    • MVP MVC MVVM中的M就是指数据类
    • Kotlin中数据类的关键字为data,一旦声明data,会自动帮我们写好下面的三个函数
    • 数据类通常需要重写equals() hashCode() toString()
    • equals()用来判断数据类是否相等
    • hashCode()是equals()的配套 还有一些HashMap HashSet的hash相关系统类需要用到
    • toString() 为了提供更好的输出日志,否则直接打印的是数据类的内存地址
点击查看代码
//JAVA中
public class Book{
  String name;
  double price;
  
  public Book(String name, double price){
      this.name = name;
      this.price = price;
  }

  @override
  public boolean equals(Object obj){
      if(obj instanceof Book){
        Book other = (Book)obj;
        return other.name.equals(name) && other.price == price;      
      }
      return false;
  }

  @override
  public int hashCode(){
    return Book.hashCode() + (int)price;
  }

  @override
  public String toString(){
    return "Book(name="+ name + ", price=" + price + ")";
  }

//尽管idea能生成代码 但是Kotlin中更为方便
data class Book(val name: String, val price: Double)
  • 单例模式
    • 单例模式:用于避免创建重复的对象 希望某个类只能拥有一个实例
点击查看代码
//JAVA
public class Singleton{
  private static Singleton instance;
  private Singleton(){}
  public synchronized static Singleton getInstance(){
          if(instance == null){
            instance = new Singleton();
          }
          return instance;
  }
  public void singleton(){
    System.out.println("singleton is called");
  }
}

/*
为了禁止外部创建Singleton类,所以将构造函数私有化 然后给外部一个get函数获取实例
然后我们判断是否存在一个实例,有就返回当前缓存中的实例,否则新建一个实例
*/

//Kotlin中
//新建时候选择Singleton 类型选Object
object Singleton{}
//这样就建好了...

8.Lambda编程

  • 集合的创建和遍历
    • 在JAVA中集合就是List(ArrayList LinkedList) Set(HashSet) Map(HashMap)

    • Kotlin中初始化集合提供了listOf(),例如 val list = listOf("apple","pear","orange") 相当于val list = ArrayList() 然后一个个add

      • 注意listOf返回的是不可变的集合,只能读取,不能修改添加删除
      • 如果需要可变的,就用mutableListOf()
      点击查看代码
        fun main(){
          val list = mutableListOf("ni","wo","ta")
          list.add("tamen")
          for(ren in list){ println(ren) }
        }
      
    • Set和list一样,只说一下概念:Set底层是hash映射机制来存放数据的,因此集合中的元素无法保证有序,这是和List不同的地方

    • Map 一种键值对结构 传统的Map是先创建一个HashMap的实例 一个个键值添加进去

      • Kotlin中可以直接用数组下表添加数据:map["me"] = 0
      • 或者 val map = mapOf("Apple" to 1, "Banna" to 2, "Orange" to 3)
      • for遍历:for((fruitm, number) in map)
    • 集合的函数式API
      lambda就是一小段可以作为参数传递的代码,正常情况下我们向函数传参时候只能传入变量,但是借助lambda就可以传入一小段代码了(一小段的定义没有强制规定,但是不推荐在lambda表达式中编写太长的代码)
      lambda表达式语法结构:

示例代码
//找名字最长的水果
val list = listOf("apple", "banana", "orange", "pear")
var maxLengthFruit =""
for(fruit in list) {
  if(fruit.length > maxLengthFruit.length) {
    maxLengthFruit = fruit
  }
}

//找最大的逻辑可以简化为如下 我也看不懂 且看后面
val maxLengthFruit = list.maxBy{ it.length }

//第一步
val maxLengthFruit = list.maxBy({fruit : String -> fruit.length})
//首先,当lambda表达式是最后一个参数时,可以将Lambda表达式移到括号外面
val maxLengthFruit = list.maxBy(){fruit : String -> fruit.length}
//接着,如果只有lambda它这一个参数,就可以省略括号
val maxLengthFruit = list.maxBy{fruit : String -> fruit.length}
//然后,lambda表达式中的参数可以不声明类型
val maxLengthFruit = list.maxBy{fruit -> fruit.length}
//最后,如果只有一个参数,都不用声明函数名,可以直接用it代替 芜湖
val maxLengthFruit = list.maxBy{ it.length }
  • JAVA函数式API的使用(仅限于Kotlin中调用Java方法,并且方法接口也是JAVA定义的)
示例 public interface Runnable{ void run(); }

//用匿名类代码创建并执行一个子线程
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("thread is running")
}
}).start()

//Kotlin取消了new 所以写法如下
Thread(Object : Runnable{
override fun run(){
println("thread is running")
}
}).start()

//使用JAVA函数式API
Thread(Runnable{
println("thread is runnning")
}).start()

//又因为lambda表达式是唯一一个参数所以可以省略括号
Thread{
println("thread is runnning")
}.start()

//Android中有一个极为常用的OnClickListener
public interface OnClickListener{
void onClick(View v);
}

button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){}
);

//kotlin只需要一行
button.setOnClickListener{}

9.空指针检查

  • 为什么有这玩意?因为Android上崩溃最高的异常类就是NullPointerException
  • 每段代码在传参的时候都需要判空,非常麻烦,所以Kotlin直接在编译时候就进行了判空的检查
示例
fun main(){
//下面这一行代码在编译的时候就会报错"NUll can not be a value of a non-null type Study"
  doStudy(null)
}

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

//如果我们希望传入的参数可以为空时 在参数声明的时候加上"?"
fun main(){
  doStudy(null)
}

fun doStudy(study: Study?){
  study.readBooks()
  study.doHomework()
}
//但是上面这样的话通过不了编译 因为可能导致空指针异常 所以要判空
fun main(){
  doStudy(null)
}

fun doStudy(study: Study?){
  if(study != null){
  study.readBooks()
  study.doHomework()}
}
  • 实际上If的判空也太啰嗦了 Kotlin中的操作符"?."即可判空
    • 例如 if(a!=null) a.xxx() 等价于 a?.xxx()
  • 另外一个操作符"?:" 如果表达式为空则返回b,否则返回a
    • 例如 val c = a ?: b 是 val c= if(a != null) a else b 的等价
  • let函数
    • obj.let
点击查看代码
fun doStudy(study: Study?){
  study?.readBooks()
  study?.doHomework()
}

//如果不用?.而用if判空
fun doStudy(study: Study?){
  if(study != null){
    study.readBooks()
  }
  if(study != null){
    study.doHomework()
  }

//用?. 和 let优化
fun doStudy(study: Study?){
    study?.let{stu ->
              stu.readBooks()
              stu.doHomework()
    }
}
/*
解释:当为空的时候什么都不做,不为空则运行let函数,let函数会把study对象传递到lambda表达式,既然传递到lambda表达式了,那就肯定不为空
*/

//又因为只有一个参数 可以简化为it
fun doStudy(study: Study?){
    study?.let{
              it.readBooks()
              it.doHomework()
    }
}

}

10.Kotlin中的其它

  • 字符串内嵌表达式(有了它就和加号连接符说拜拜了)
    • 语法规则"hello, ${obj.name} nice to meet you"
    • 当只有一个变量的时候可以省略大括号"hello, $name nice to meet you"
示例代码
println("Book(name=" + name + ", price=" + price + ")")
//用$
println("Book(name=$name,price=$price)")
  • 给函数参数设定默认值
点击查看代码
fun printParams(num: Int, str: String = "hello"){
println("num is $num, str is $str"
}

//在调用的时候为了防止赋值给错误参数类型,造成值和类型不匹配,可以直接指定名字进行赋值
printParams(str = "haoye!")
  • Kotlin中的bean
    • 在JAVA中一个类只含有私有的属性,然后有对应的set和get方法,这个类称为Java Bean.
    • 在Kotlin中不需要写出来set和get方法,它会自动生成和调用,代码如下
点击查看代码
//在下面的代码里虽然没有显式调用get和set方法
//但是实际上在背后将代码转换成了调用那两个方法
val book = Book()
book.pages = 500
val bookPages = book.pages
  • 标准函数和静态方法
    • 标准函数:Standard.kt文件中定义的函数
    • 常用的标准函数:
      • with(anytype, Lambda_expression)
        从Lambda中提供第一个参数对象的上下文,并使用Lambda表达式中 最后一行代码作为返回值
        作用:在连续调用同一个对象的多个方法时精简代码

      • run函数
        并不直接调用,在某个对象基础上调用,其次run()仅接收一个lambda参数,并且在lambda表达式中提供调用对象的上下文,其它方面和with函数一样

代码示例 ``` //一个水果列表 吃完所有水果并打印结果 val list = listOf("apple","pear","orange") val builder = StringBuilder() builder.append("start eating\n") for(fruit in list){ builder.append(fruit).append("\n") } builder.append("Ate all fruits") vak result = builder.toString() println(result)

//实际上上述代码调用了多次append
val result = with(StringBuilder()){
append("start eating\n")
for (fruit in list){
append(fruit).append("\n")
}
append("ate all")
toString()
}
/*
代码阐释,with中使用了StringBuilder()作为下面对象的上下文
所以不用在拿Builder去调用append\toString方法,直接用就好了
然后Lambda表达式的最后一行代码作为返回值返回
*/

//run()
val result = obj.run{
"value"//返回值
}


</details>
posted @ 2022-03-20 20:36  WriteOnce_layForever  阅读(180)  评论(0编辑  收藏  举报