kotlin 学习笔记(一)
笔记整理至极客时间《快速上手kotlin开发》,本文整理至1~10集系列视频。
变量声明
//var <变量名> 类型 = ...
//结尾不需要分号
var name: String = "zhangsan"
//也可以利用类型自动判断,省去类型
var name = "zhangsan"
函数
//函数写法和golang有点像,返回值在入参列表的后面
//入参: name
//返回值: String 类型
//字符串拼接不需要像java里一样的String.format("hello %s", name), 和shell脚本一样,比较方便
fun sayHello(name: String): String {
return "hello $name"
}
类扩展
扩展函数
假设有自定义类在文件TeacherService.kt
中
class TeacherService(private val student: Student) {
fun sHello() {
student.hello()
}
}
下面针对这个类进行扩展 e.kt
public fun TeacherService.getStudentName():String = "hello"
public fun TeacherService.fuza(name: String = "haha"):String {
return name
}
可进行如下测试
var ts = TeacherService(Student())
ts.sHello()
println(ts.getStudentName())
println(ts.fuza())
下面针对jdk标准类库进行扩展
fun <T> Collection<T>.joinToString(
separator: String = ",",
prefix: String = "",
postfix: String = ""
): String{
val result = StringBuilder(prefix)
for ((index, value) in this.withIndex()) {
if (index > 0) {
result.append(separator)
}
result.append(value)
}
result.append(postfix)
return result.toString()
}
测试
println(listOf("a", "b", "c").joinToString(prefix = "[", postfix = "]"))
kotlin里,针对jdk的许多标准库进行了函数扩展,比如 FileReadWrite.kt
当然扩展函数,只是相当于在扩展类里面添加的静态方法,如果用java代码进行调用,就没什么黑魔法了
TeacherService ts = new TeacherService(new Student());
ts.sHello();
EKt.getStudentName(ts);
扩展属性
相关文档里讲,属性也是可以扩展的,但是研究了一下,有一点不明白属性扩展能做啥
var String.s: Int
get() = this.length
set(value){
//set方法并没有field可以用来存储value,
//其实际作用是使用通过value来操作调用者,即this
println(this.plus(value))
}
Lambda 闭包
var hello = {s: String -> println(s)}
fun main(args: Array<String>) {
hello("hah")
}
最基本的lambda写法
fun main(args: Array<String>) {
val thread = Thread({ -> Unit })
thread.start()
}
如果没有参数,可以省略箭头符号 ->
fun main(args: Array<String>) {
val thread = Thread({ })
thread.start()
}
如果lambda是函数的最后一个参数,可以将大括号放在小括号外部
fun main(args: Array<String>) {
val thread = Thread(){}
thread.start()
}
如果函数只有一个参数切这个参数是lambda,可以省略小括号
fun main(args: Array<String>) {
val thread = Thread{}
thread.start()
}
为什么在lambda上玩出这么多花头精?因为想支持函数式编程,必须要简洁,java原生的匿名内部类写法太过臃肿,java8之后出的lambda有一些改善,kotlin在此基础上进行更加好的改善。
为什么要匿名内部类?主要在两个领域会经常用到匿名内部类
- 移动端开发,各种注册listener
- 异步编程,各种回调函数
java或者说jvm体系,没有函数
的概念,只有方法
, 想要支持函数式编程,jvm体系上,基本上是基于匿名内部类来实现的,kotlin里在kotlin.jvm.functions
包里内置了很多的Function
接口,无非是让人感觉像
是在写函数。
高阶函数
传入函数
把函数传给函数(jvm层面,无非是把一个对象传给一个函数,实现一种回调的效果)
fun main(args: Array<String>) {
onlyif(true) {
println("ddd")
}
}
fun onlyif(isDebug: Boolean, block: () -> Unit){
if(isDebug) block()
}
所以,如果大量使用高阶函数,就会造成大量的临时对象产生(没有追求性能极致,貌似也没什么问题),所以kotlin里发明了inline
关键字。
返回函数
(想起了早些年写的js,记得js里为了实现某一种封装,是通过返回一个函数来实现的)
fun main(args: Array<String>) {
println(doSth()())
}
fun doSth(): () -> String {
var name = "xiaoming"
return {name}
}
构造函数
定义父类和接口
//open 的类才能被继承
open class Person {
//open的方法才能被覆盖
open fun sayHi(){
println("hello")
}
}
interface Runer {
fun run()
}
实现父类和接口
class Student(var name: String) : Person(), Runer {
//构造函数执行的时候,init代码块里的代码将被执行(不管是主构造函数还是次级构造函数)
init {
println(name)
}
//主构造函数的name,不需要额外声明;次级构造函数的参数需要额外声明
var age: Int = 0
/**
* 次级构造函数必须直接或间接的继承主构造函数或父级构造函数
*/
constructor(name: String, age: Int) : this(name) {
this.age = age
}
//覆盖父类的方法,必须带override关键字
override fun sayHi() {
println("hi I'm $name, I'm $age years old")
}
override fun run() {
// TODO("not implemented") 这个TODO是可以编译通过的,运行时报错
println("student run")
}
}
伴生对象
静态工具类
//通过伴生对象来做
class StringUtils {
companion object {
fun isEmpty(str: String) : Boolean {
return "" == str
}
}
}
//通过jvmStatic注解来做
object XXUtils {
@JvmStatic
fun isBlank(str: String) : Boolean {
return "" == str
}
}
fun main(args: Array<String>) {
println(StringUtils.isEmpty(""))
println(XXUtils.isBlank("abc"))
}
单例
class Student private constructor() {
companion object {
fun get() :Student {
return Holder.instance
}
}
private object Holder {
var instance: Student = Student()
}
}
fun main(args: Array<String>) {
println(Student.get())
println(Student.get())
}
关于object的修饰符
- object修饰一种特殊的类,类里的属性和方法都是静态的
- 如果object放在一个类的内部,那就是一个静态内部类,除非用
inner
修饰 - 参考
网友评论