1.初识Kotlin


概述:

  1. 编程语言分为两种:编译型语言解释型语言
    编译型语言:编译器将编写的源代码一次性编译成计算机可识别的二进制文件,然后计算机直接执行。
    解释型语言:有一个解释器,程序运行时解释器一行行读取编写的源代码,实时将这些源代码解释成计算机可识别的二进制数据后再执行
  2. java代码编译之后生成一种特殊的class文件,只有Java虚拟机才能识别,这个Java虚拟机担当的是解释器的角色,Java属于解释型语言。
  3. Kotlin工作原理:
    开发了一门新的编程语言,然后自己做了编译器,让它将这门新语言的代码编译成同样规格的class文件,只要是符合规格的class文件,java虚拟机都能识别
  4. Kotlin优点
    语法简单,没有分号,语法高级,增加了很多现代高级语言的语法特性,开发效率大大提升,更安全,几乎杜绝了空指针异常,和Java百分百兼容

1 变量

两种关键字

关键字是否可变
val(value)声明一个不可变的变量 ,初始赋值后再也不能重新赋值,对应java中的final变量
var (variable)声明一个可变的变量,初始赋值后还能重新赋值,对应java中的非final变量

注意:永远优先使用val声明变量,当val无法满足需求时再使用var

1.2 数据类型

Kotlin使用了对象数据类型,Java中int是关键字,Kotlin中Int是一个类,拥有自己的方法和继承结构

2 函数

2.1 概念

函数和方法是同一个概念,是用来运行代码的载体

fun methonName(param1: Int, param2 :Int):Int{
	return 0;
}

fun:定义函数的关键字
methonName:函数名
(param1: Int, param2 :Int):声明函数接收什么参数
Int:返回的数据类型

2.2 语法糖

当一个函数中只有一行代码时,可以不必编写函数体,直接将唯一的一行代码写在函数尾部,中间用等号连接

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

Kotlin的类型推导机制:

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

3 程序的逻辑控制

3.1 if条件语句

fun largerNumber(num1:Int,num2:Int):Int {
	var value=0;
	if(num1 > num2){
		value = num1;
	}else{
		value = num2;
	}
	return value;
}

if语句是可以有返回值的,返回值是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
}

3.2 when语句

用一个例子解释它的用法:
用if语句写:

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"->100
    else ->0
}
  1. when语句有返回值
  2. 匹配值 -> { 执行逻辑 }
  3. when语句还允许进行类型匹配
    例如:
fun checkNumber(num:Number){
    when (num){
        is Int -> println("number is Int");
        is Double ->println("number is Double");
        else ->println("number not support");
    }
}
1.is关键字是类型匹配的核心 = java中的Instanceof关键字
2.Number类型的参数,Kotlin内置的一个抽象类,Int,Float,Double等与数字相关的类都是它的子类

3.3 循环语句

3.3.1 while循环没有区别

3.3.2 for-in 循环

…关键字——两端闭区间

val range = 0…10,相当于[0,10],…是创建两端闭区间的关键字

fun main(){
    for(i in 0..10){
        println(i)
    }
}
until关键字——左闭右开的区间

val range = 0 until 10,相当于[0,10)

step关键字——跳过一些元素
fun main(){
    for(i in 0 until 10 step 2){
        println(i)
    }
}
downTo关键字——降序的区间

i in 10 downTo 1 = [10,1]

4.面向对象编程

4.1 类与对象

面向对象的语言可以创建类,类是对事物的一种封装,如人,汽车,房子等都可以将它封装成一个类,类通常是名词,类中可以拥有自己的字段和函数,字段:该类拥有的属性,字段名通常是名词,函数:该类可以拥有的行为,函数名通常是动词。通过这种类的封装,我们可以在适当的时候创建该类的对象,调用对象中的字段和函数满足实际编程的要求。

package com.example.test1

class Person {
    var name = ""
    var age = 0

    fun eat(){
        println(name + "is eating . He is "+ age + "year old.")
    }
}

对这个类进行实例化和一些操作

    val p = Person()
    p.name = "Jack"
    p.age = 19
    p.eat()

输出
在这里插入图片描述

4.2 继承与构造函数

4.2.1 继承

写一个Student类,继承Person类,这样Student类就自动拥有了Person中的字段和函数,另外还可以定义自己独有的字段和函数

class Student {
    var sno = ""
    var grade = 0
}
1. 使Person类可以被继承
在Kotlin中任何一个非抽象类默认都是不可以被继承的,相当于Java中给类声明了final关键字。抽象类本身是无法创建实例的,一定要有子类去继承它才能创建实例,因此抽象类必须可以被继承。

加上open关键字

open class Person {
...
}
2. 继承,extends变成:
class Student : Person(){
    var sno = ""
    var grade = 0
}

4.2.2 构造函数

Kotlin将构造函数分为主构造函数次构造函数

主构造函数:没有函数体,直接定义在类名的后面
class Student(val sno : String, val grade :Int):Person(){
}
//进行实例化:
val student = Student("a123",5)

主函数没有函数体,想在主构造函数中编写一些逻辑,init结构体

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

子类的构造函数必须调用父类中的构造函数,子类的主构造函数调用父类中的哪个构造函数,在继承的时候通过括号来指定。
上面代码Person类后面的()表示Student类的主构造函数在初始化的时候会调用Person类的无参构造函数
修改一下:

open class Person(val name:String,val age:Int) {
}
class Student(val sno:String, val grade:Int, name:String, age:Int):
        Person(name,age){
}

注意:在主构造函数中声明成val或var的参数将自动成为该类的字段,会导致和父类中同名的name和age字段造成冲突,这里name,age前面不加任何关键字,让他的作用域仅限定在主构造函数中即可。
创建实例:

val student = Student("a123",5,"Jack",9)
次构造函数
  1. 任何一个类只能有一个主构造函数,但可以有多个次构造函数,次构造函数可以用于实例化一个类,有函数体。
  2. 当一个类既有主构造函数又有次构造函数时,所有次构造函数都必须调用主构造函数
  3. 次构造函数通过constructor关键字来定义
class Student(val sno:String, val grade:Int, name:String, age:Int):
        Person(name,age){
    constructor(name: String,age: Int):this("",0,name,age){ //通过this关键字调用了主构造函数
    }
    constructor():this("",0){  //调用了第一个次构造函数,间接调用了主构造函数
    }
}

4.当类中只有次构造函数,没有主构造函数

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

没有主构造函数,继承Person类的时候不需要加上括号,次构造函数只能调用父类的构造函数,用了super关键字

4.3 接口

接口:用于实现多态编程的重要组成部分
Java是单继承结构语言,任何一个类最多只能继承一个父类,但是可以实现任意多个接口,可以在接口中定义一系列的抽象行为,然后由具体的类去实现
例子:

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

//让Student类去实现Study接口
class Student(name: String,age: Int):Person(name,age),Study{
    override fun readBooks() {
        println(name+" is reading")
    }

    override fun doHomework() {
        println(name + " is doing homework")
    }
}
//调用
fun main(){
    val student = Student("Jack",19)
    student.readBooks()
    student.doHomework()
}

override关键字重写父类或者实现接口中的函数
这种叫做面向接口编程,也叫多态
也可以对接口中的函数进行默认实现

4.4 函数的可见性修饰符

在这里插入图片描述

4.5 数据类

数据类:将服务器端或数据库中的数据映射到内存中,为编程逻辑提供数据模型的支持
数据类通常需要重写equals(),hashCode(),toString()这几个方法

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

data:关键字,希望这个类是一个数据类,equals(),hashCode(),toString()等固定且无实际逻辑意义的方法自动生成
测试:

fun main(){
    val cellphone1 = Cellphone("Samsung",1299.99)
    val cellphone2 = Cellphone("Samsung",1299.99)
    println(cellphone1)
    println(cellphone1 == cellphone2)
}

在这里插入图片描述

4.6 单例类

单例模式:避免创建重复对象

Java:

public class Singleton {
     private static Singleton instance;

     private Singleton(){} 
     //禁止外部创建Singleton实例,private关键字将构造函数私有化
	 //给外部提供了一个getInstance()静态方法用于获取Singleton的实例
     public synchronized static Singleton getInstance(){ 
         if(instance!=null){
             instance = new Singleton();
         }
         return instance;
     }

     public void singletonTest(){
         System.out.println("SingleTonTest is called. ");
     }
}

//要使用单例中的方法时
Singleton singleton = Singleton.getInstance();
singleton.singletonTest();

Kotlin:
object关键字

object Singleton {
    fun singletonTest(){
        println("SingleTonTest is called. ")
    }
}
//调用
Singleton.singletonTest()

4.7 Lambda编程

简介

Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。

JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。

对接口的要求

  1. Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法
  2. jdk 8 中有另一个新特性:default, 被 default 修饰的方法会有默认实现,不是必须被实现的方法,所以不影响 Lambda 表达式的使用。
  3. @FunctionalInterface修饰函数式接口的,要求接口中的抽象方法只有一个。 这个注解往往会和 lambda 表达式一起出现。

4.7.1 集合的创建与遍历

List,Set,Map在Java中都是接口
List的主要实现类:ArrayList和LinkedList,Set:HashSet,Map:HashMap
listOf函数,创建的是一个不可变的集合,只能用于读取

    val list = listOf("Apple","Banana","Orange","Pear")
    for (fruit in list){
        println(fruit)
    }

mutableListOf()函数,创建的是可变集合
Set集合setOf()mutableSetOf(),注意Set集合底层是使用hash映射机制来存放数据的,集合中的元素无法保证有序,这是与List的不同
Map集合:

//写法1:
    val map = HashMap<String,Int>()
    map["Apple"] = 1
    map["Banana"] = 2
    map["Orange"] = 3
    map["Pear"] = 4
    map["Grape"] = 5
//写法2:
    val map = mapOf("Apple" to 1,"Banana" to 2)
    for((fruit,number) in map){
        println("fruit is "+fruit+" , number is "+number)
    }

4.7.2 集合的函数式 API

例子:找出长度最长的水果单词:

//普通写法
    val list = listOf("Apple","Orange","Banana","Pear","Grape","Watermelon")
    var maxLengthFruit = ""
    for (fruit in list){
        if(fruit.length > maxLengthFruit.length){
            maxLengthFruit = fruit
        }
    }
    println("max length fruit is "+maxLengthFruit)
//集合的函数式API
    val list = listOf("Apple","Orange","Banana","Pear","Grape","Watermelon")
    var maxLengthFruit = list.maxBy { it.length }
    println("max length fruit is "+maxLengthFruit)


Lambda

Lambda就是一小段可以作为参数传递的代码
{ 参数名1: 参数类型 , 参数名2: 参数类型 -> 函数体 }
->符号表示参数列表的结束以及函数体的开始,函数体中可以编写任意行代码,最后一行代码会自动作为Lambda表达式的返回值

//maxBy,函数,接收的是一个Lambda类型的参数,
//遍历集合时将每次遍历的值作为参数传递给Lambda表达式
//工作原理:根据我们传入的条件来遍历集合,从而找到该条件下的最大值

//1.
    val list = listOf("Apple","Orange","Banana","Pear","Grape","Watermelon")
    val lambda = { fruit:String ->fruit.length }
    val maxLengthFruit = list.maxBy (lambda)
//2.简化
	val maxLengthFruit = list.maxBy({fruit:String -> fruit.length})
//3.简化——当Lambda参数是函数的最后一个参数时,将Lambda表达式移到函数括号的外面
	val maxLengthFruit = list.maxBy(){fruit:String -> fruit.length}
//4.简化——当Lambda参数是函数的唯一一个参数时,将函数的括号省略
	val maxLengthFruit = list.maxBy{fruit:String -> fruit.length}
//5.简化——类型推导机制
	val maxLengthFruit = list.maxBy{fruit-> fruit.length}
//6.简化——当Lambda表达式的参数列表中只有一个参数时,不必声明参数名,可以使用it关键字来代替
	val maxLengthFruit = list.maxBy{ it.length }
map函数

将集合的每个元素都映射成一个另外的值

    val list = listOf("Apple","Orange","Banana","Pear","Grape","Watermelon")
    val newList = list.map { it.toUpperCase() }
    for (fruit in newList){
        println(fruit)
    }
filter函数

过滤集合中的数据

//保留5个字母以内的水果
    val list = listOf("Apple","Orange","Banana","Pear","Grape","Watermelon")
    val newList = list.filter { it.length <5 }
    for (fruit in newList){
        println(fruit)
    }
any——集合中是否存在一个元素满足指定条件
all——集合中是否所有元素都满足指定条件
    val list = listOf("Apple","Orange","Banana","Pear","Grape","Watermelon")
    val anyResult = list.any { it.length<=5 }
    val allResult = list.all { it.length <=5 }

4.7.3 Java函数式API的使用

在Kotlin中调用了一个Java方法,并且该方法接收一个Java单抽象方法接口参数,就可以使用函数式API。Java单抽象方法接口——接口中只有一个待实现方法

最常见的单抽象方法接口——Runnable接口

public interfac Runnable{
	void run();
}

对于任何一个Java方法,只要它接收Runnable参数,就可以使用函数式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")
        }
    }).start()
//化简
    Thread(Runnable { 
        println("Thread is running")
    }).start()
//化简参数列表中有且仅有一个Java单抽象方法接口参数,将接口名省略
    Thread( { 
        println("Thread is running")
    }).start()
//最终化简
    Thread{
        println("Thread is running")
    }.start()

注意:本节中的Java函数式API使用都限定从Kotlin中调用Java方法,并且单抽象方法接口也必须是用Java语言定义的

4.8 空指针检查

4.8.1 可空类型

Kotlin默认所有的参数和变量都不可为空
为空的类型系统:在类名后面加上问号

	fun main(){
	    doStudy(null)
	}
	
	fun doStudy(study: Study?){
	    if(study!=null){
	        study.doHomework()
	        study.readBooks()
	    }
	}

4.8.2 判空辅助工具

?.操作符

if(a!=null){
	a.doSomething()
}
即
a?.doSomething()

?: 操作符

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

辅助工具——let

是一个函数,这个函数提供了函数式API的编程接口
而且可以处理全局变量的判空问题,if是无法解决的

fun doStudy(study:Study?){
	study?.let{ stu ->  //对象为空时什么都不做,不为空时调用let函数
						//let函数将study对象本身作为参数传递到Lambda表达式中
						//study的对象肯定不为空
		stu.readBooks()
		stu.doHomework()
	}
}

4.9 字符串内嵌表达式——${}

当表达式中仅有一个变量的时候,将两边的大括号省略

fun main(){
    doStudy(null)
    val name = "Tome"
    val age = 19
    println("name $name ,age $age")
}

4.10 函数的参数默认值

可以给函数设定参数默认值

	printParams(str = "world",name = 123)
//不管哪个参数在前还是在后,都可以准确将参数匹配上
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值