Kotlin基础笔记(一)

一、变量和方法

变量

Kotlin中定义一个变量,只允许在变量前声明两种关键字:valvar

val(value的简写)用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能重新赋
值,对应Java中的final变量。

var(variable的简写)用来声明一个可变的变量,这种变量在初始赋值之后仍然可以再被重新
赋值,对应Java中的非final变量。

Kotlin 可以不需要定义类型,会自动推导类型。

    val a = 22
    println("a = " + a)

如果要对一个变量延迟赋值,需要显式地声明变量类型。

	var b: Int = 0

相对于Java中的基本数据类型,Kotlin全部使用了对象数据类型。

KotlinIntLongShortFloatDoubleBooleanCharByte
Javaintlongshortfloatdoublebooleancharbyte

可见性修饰符

修饰符JavaKotlin
public所有类可见所有类可见(默认)
private当前类可见当前类可见
protected当前类、子类、同一包路径下的类可见当前类、子类可见
default同一包路径下的类可见(默认)
internal同一模块中的类可见

方法

关键字fun用来声明方法,参数的声明格式是“参数名: 参数类型”,括号后面的用于声明返回类型。

	fun maxNumber(num1: Int, num2: Int): Int {
		
	    return if (num1 > num2) {
	        num1
	    } else {
	        num2
	    }
	}

Kotlin的if语句可以有返回值,返回值是每个条件的最后一行代码。

当方法中只有一行代码时,可以直接将这行代码写在方法定义的尾部,中间用等号连接。

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

when

相对于Java中的switch语句,Kotlin中使用when语句

	fun getScore(name: String) = when (name) {
	    "Tom" -> 93
	    "Sam" -> 84
	    "Jack" -> 52
	    else -> 0
	}

循环语句

区间: Kotlin中引入了区间的使用,创建两端闭区间的关键字是..,相当于数学中的[1, 10]

    val range = 1..10

for循环取消了 for-i 循环,使用 for-in 循环

	for(i in 1..10) {
        println(i)
    }

until关键字,表示区间左闭右开,相当于数学中的[0, 10)

	val ru = 0 until 10

step关键字,递增的步数,相当于for-i中的 i = i + 2

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

downTo关键字,降序区间,相当于for(i = 5; i >= 1; i--)

    for (i in 5 downTo 1) {
        println(i)
    }

二、对象

class Person {
}

val p = Person()

继承和构造方法

Kotlin中任何一个非抽象类默认都是不可以被继承的,想要被继承要在前面加上open关键字

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

    fun eat() {
        println(name + " is eating. He is " + age + " years old.")
    }
}
  • Java继承的关键字是extends,而在Kotlin中变成了一个冒号
  • kotlin的构造函数分为 主构造函数次构造函数
  • 主构造函数的特点是没有函数体,直接定义在类名的后面即可。比如Student这种写法
  • 如果想在主构造函数中编写一些逻辑,Kotlin提供了一个init结构体
  • 像java一样子类中的构造函数必须调用父类中的构造函数,但是主构造函数没有构造方法,所以 Person 后面的括号表示调用哪一个构造方法
class Student(val sno: String, val grade: Int) : Person(){
    var sno = ""
    var grade = 0

    init {
        println("grade is " + grade)
    }
}

主构造函数中显示指明参数

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

主构造函数中声明成val或者var的参数将自动成为该类的字段,比如上面父类中的name和age,所以下面子类中的name和age不能加任何关键字,否则和父类冲突。

  • 次构造函数是通过constructor关键字来定义的
  • 所有的次构造方法都必须调用主构造方法(包括间接调用)
class Student2(val son: String, val grade: Int, name: String, age: Int) : Person2(name, age) {

    constructor(name: String, age: Int) : this("", 0, name, age) {
    }
}

少见的特殊情况
一种非常特殊的情况:类中只有次构造函数,没有主构造函数,这种不常用
在次构造方法中还是要用super调用了父类的构造方法

class Student3 : Person2 {
    constructor(name: String, age: Int) : super(name, age) {

    }
}

方法的参数默认值

在定义方法时可以给任意参数设定默认值,这样就不会强制要求为此参数传值,在没有传值的情况下会自动使用参数的默认值。

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

当设定默认值的参数是最后面的参数时,可以直接省略掉

	printParams(5)

当设定默认值的参数不是最后面的时候,可以通过键值对方式来传参调用。

	printParams(num = 99, str = "abc")
	printParams(str = "abc")

给方法设定参数默认值和键值对方式传参,很大程度上替代类的次构造方法。

接口

interface Study {
    fun readBook()
    fun doHomeWork()
}

Java中继承的关键字是extends,实现接口的关键字是implements,而Kotlin中统一使用冒号:,中间用逗号进行分隔。

class Student4(name: String, age: Int) : Person2(name, age), Study {
    override fun readBook() {
        println(name + " is reading")
    }

    override fun doHomeWork() {
        println(name + " doing homework")
    }
}

数据类

data关键字表示是一个数据类,会自动生成equals()、hashCode()、toString()等

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

使用举例

    val phone1 = CellPhone("Xiaomi", 1999.5)
    val phone2 = CellPhone("Xiaomi", 1999.5)
    println(phone1)
    println(phone1 == phone2)

输出

	CellPhone(brand=Xiaomi, price=1999.5)
	true

单例

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

关键字object表示创建单例类,不加class关键字。

Singleton.singletonTest()

调用虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了一个Singleton类的实例。

三、集合

List

使用listOf()方法创建一个不可变的集合,只能读取不能增删改

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

使用mutableListOf()函数创建一个可变的集合

    val list2 = mutableListOf("Apple", "Banana", "Orange", "Pear")
    list2.add("Grape")

Map

Kotlin中的Map推荐使用一种类似于数组下标的语法结构

    val map = HashMap<String, Int>()
    //添加
    map["Apple"] = 1
    map["Banana"] = 2
    map["Orange"] = 3

	//读取
	val number = map["Banana"]
    
    //遍历
    for ((fruit, number) in map) {
        println(fruit + number)
    }

简化用法,可以直接传入初始化的键值对组合来完成对Map集合的创建。

    val map2 = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3)

Lambda表达式

Lambda就是一小段可以作为参数传递的代码。
语法结构:
{ 参数名1: 参数类型, 参数名2: 参数类型 -> 函数类体 }

示例:找到字符串集合中最长的那个

这里用到的maxByOrNull()就是一个普通方法,它接收的是一个Lambda类型的参数,并且会在遍历集合时将每次遍历的值作为参数传递给Lambda表达式。

    val list = listOf("Apple", "Banana", "Pear", "Watermelon")
    val lambda = { fruit: String -> fruit.length }
    val maxLengthFruit = list.maxByOrNull(lambda)

Kotlin规定,当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面。所以简化为

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

如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略,Lambda表达式中的参数列表其实在大多数情况下不必声明参数类型,简化:

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

当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替,简化:

    val maxLengthFruit = list.maxByOrNull { it.length }

函数式API

map()

集合中的map()函数是最常用的一种函数式API,它用于将集合中的每个元素都映射成一个另外的值,映射的规则在Lambda表达式中指定,最终生成一个新的集合。

示例:让集合中的字符串都变成大写

	val list = listOf("Apple", "Banana", "Pear", "Watermelon")
    val newList = list.map { it.uppercase()}
    for (fruit in newList) {
        println(fruit)
    }

filter()

filter函数用来过滤集合中的数据。

示例:输出长度小于等于5的字符串并大写

	val list = listOf("Apple", "Banana", "Pear", "Watermelon")
    val list2 = list.filter { it.length <= 5 }
        .map { it.uppercase() }

any()和all()

any函数用于判断集合中是否至少存在一个元素满足指定条件,all函数用于判断集合中是否所有元素都满足指定条件。

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

输出结果

any is true, all is false

Java函数式API的使用

如果我们在Kotlin代码中调用了一个Java方法,并且该方法接收一个Java单抽象方法接口参数,就可以使用函数式API。Java单抽象方法接口指的是接口中只有一个待实现方法,如果接口中有多个待实现方法,则无法使用函数式API。

示例:
创建子线程Java写法

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

翻译成Kotlin写法,由于Kotlin舍弃了new关键字,因此创建匿名类实例改用object关键字。

    Thread(object : Runnable{
        override fun run() {
            println("running")
        }
    }).start()

简化:

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

同理点击事件监听简写:

	button.setOnClickListen {
	}

四、空指针检查

Kotlin默认所有的参数和变量都不可为空,当需要为空时,类名的后面加上一个问号表示可空类型。
例如Int表示不可为空的整型,而Int?就表示可为空的整型;String表示不可为空的字符串,而String?就表示可为空的字符串。

判空辅助工具

操作符?.表示当对象为空时则什么都不做

	a?.doSomeing()

操作符?:表示如果左边的结果不为空就返回左边,否则就返回右边的结果。

	val c = a ?: b

非空断言!!表示相信对象不会为空,强行编译通过。

	a!!.doSomeing()

let

let函数提供了函数式API的编程接口,并将原始调用对象作为参数传递到Lambda表达式中。

	obj.let { o ->
		//编写逻辑代码
	}

结合?.进行非空判断

	study?.let {
		it.readBook()
		it.doHomework()
	}

五、其他

标准函数with、run和apply

Kotlin的标准函数指的是Standard.kt文件中定义的函数,任何Kotlin代码都可以自由地调用所有的标准函数。

with
with函数接收两个参数:第一个参数可以是一个任意类型的对象,第二个参数是一个Lambda表达式。会在Lambda表达式中提供第一个参数对象的上下文,并使用Lambda表达式中的最后一行代码作为返回值返回。

示例:拼接字符串

    val array = listOf("Apple", "Pear", "Banana", "Grape")
    val result = with(StringBuilder()) {
        append("start eat\n")
        for (s in array) {
            append(s).append("\n")
        }
        append("end").toString()
    }
    println(result)

Lambda表示中有StringBuilder对象的上下文,所以可以直接调用方法,最后一行返回结果。

run
run函数通常不会直接调用,而是要在某个对象的基础上调用,其他方面和with函数是一样的。

    val array = listOf("Apple", "Pear", "Banana", "Grape")
    val result = StringBuilder().run {
        append("start eat\n")
        for (s in array) {
            append(s).append("\n")
        }
        append("end").toString()
    }
    println(result)

apply
applyrun差不多,只是无法指定返回值,而是会自动返回调用对象本身。

    val array = listOf("Apple", "Pear", "Banana", "Grape")
    val result = StringBuilder().apply {
        append("start eat\n")
        for (s in array) {
            append(s).append("\n")
        }
        append("end")
    }
    println(result.toString())

静态方法

Kotlin却极度弱化了静态方法这个概念,非常推荐使用单例类的方式来实现。

如果只是要在普通类中定义静态方法可以使用companion object里面定义方法。

class Fish {

    companion object {

        fun doAction() {

        }
    }

}

companion object实际上不是真正的静态方法,当在Java代码中时无法调用的。
真正的静态方法有两种方式 注解顶层方法
注解:

    companion object {
        @JvmStatic
        fun doAction() {
        }
    }

单例类companion object 中的方法加上@JvmStatic注解,那么Kotlin编译器就会将这些方法编译成真正的静态方法。

顶层方法
顶层方法指的是那些没有定义在任何类中的方法,直接写在kotlin文件中的。
在kotlin代码中任何位置都可以直接调用,在Java代码中要使用文件名来调用。

const

const关键字是用来定义常量,只有在单例类companion object顶层方法中才可以使用。

官方文档:用于修饰在编译时已知的只读属性。

使用

	const val PARAM_DATA = "param_data"

翻译成Java为:

	public static final String PARAM_DATA = "param_data";

lateinit

lateinit关键字是用来延迟初始化。

    private lateinit var adapter: ChatMsgAdapter

判断变量是否已经被初始化,::变量.isInitialized

        if (!::adapter.isInitialized) {
            adapter = ChatMsgAdapter(list)
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值