前言: 用了 kotlin 差不多半年时间了,之前是看了中文版的 kotlin 入门的,后面使用的时候总感觉有些细节的东西并没有很好的理解,专门买了份 kotlin 的教程,感觉不错,本文也是中途一些细节的整理。
var 用 lateinit 延迟初始化, val 用 lazy 延迟初始化 ? 表示可空类型,类型后面不跟 ? 表示不可空类型 ?. 表示若为 null ,则返回 null ,否则返回返回对象继续逻辑操作。 !!. 表示强制认定为不为 null 使用但是最好自己做一下判断,不然等下抛空异常 ?: 表示当前面为 null 的时候,返回 ?: 后面的值 class X
lateinit var mStr:String //var 延迟初始化
val x:X by lazy{ // val延迟初始化
X()
}
var name: String? = ""
fun a(x: Any): Int {
return name?.length ?: 0
}
val nullable:String? = null //正确 可以为空
val notNull:String = null //报错 不能为空
nullable.length //错误 ,不可以直接使用
notNull.length //正确,不可空的值可以直接使用
nullable!!.length //正确,强认定不为null
nullable?.length //正确,若nullable为空
nullable?.length ?: -1
复制代码
as 类型转换 跟java的类型转换一样,失败则抛异常 as? 安全类型转换,转换失败返回null,不会抛异常
val stub:Childen = parent as Childen //转换失败 stub不会返回空,会抛异常 val stub:Childen = parent as? Childen //转换失败 stub 可以返回空 复制代码
ClosedRange 的子类, IntRange 最用
0..100 表示 [0,100] 0 until 100 表示 [0,100) i in 0..100 判断是否在区间 [0,100] 中 val range:IntRange = 0..1024 //[0,1024] val range_exclusive:IntRange = 0 until 1024 //[0,1024) = [0,1023] val emptyRange:IntRange = 0...-1 //空区间 emptyRange.isEmpty() //判断区间是否为空 //迭代 for(i in range) 复制代码
基本写法: val array:Array<类型> = arrayOf(类型的对象1,类型的对象2,.....) 基本操作: array[i] :输入第 i 个成员 array[i] = 新的类型对象 给第 i 个成员赋值
array.slice() 截取 可传入 区间 eg:0..10 或者 0 until 100 array.joinToString() 转化成 String 下面是对应的参数 -- separator: CharSequence :分隔符 默认为 , -- prefix: CharSequence : 增加前缀 默认为 "" -- postfix: CharSequence :增加后缀 默认为 "" -- limit: Int :截取位置(从1开始而不是从0开始) -- truncated :被limit截取后,后面展示什么 -- transform : 每个元素进行处理返回处理后的数据 具体例子展示:
val arrayOfInt: IntArray = intArrayOf(1,3,5,7)
val arrayOfChar: CharArray = charArrayOf('H', 'e','l','l','o','W','o','r','l','d')
val arrayOfString: Array<String> = arrayOf("我", "是", "码农")
fun main() {
System.out.println(arrayOfString.joinToString(""))
var i:IntRange = 0..100
System.out.println(arrayOfChar.slice(0..7))
var array1 = arrayOfString.joinToString("","前缀","后缀",2,"后面省略",transform = {
//转换
return@joinToString it+"转换"
})
var array2 = arrayOfString.joinToString("","前缀","后缀",3,"后面省略",transform = {
//转换
return@joinToString it+"转换"
})
println(array1)
println(array2)
}
-------------------------------------打印出来的log
我是码农
[H, e, l, l, o, W, o, r]
前缀我转换是转换后面省略后缀
前缀我转换是转换码农转换后缀
复制代码
val TAG = "str" 并不等价与 java中的 public final String TAG = "str" 如果要等价的话 const val TAG = "str" 复制代码
具体的可以看一下反编译 val TAG = "str" 的字节码跟 public final String TAG = "str" 有什么不同~ 里面可以看到 val 虽然不可赋值,但是它并不是编译器常量,而是一个变量。也就是编译期并不是替换成常量来进行的,所以后期还是可以经过反射进行修改! 如果要像java中定义出编译期常量的话 public final String TAG = "str" 则需要使用到 const 这里反编译出来的跟 java 中的就类似了。
本质函数也是一个成员,只不过它是一段代码块
val int2Long = fun(x:Int):Long{
return x.toLong()
}
复制代码
本质:匿名函数 写法:{[参数列表]->[函数体,最后一行还是返回值]} 举例: val sum = {a:Int,b:Int ->a+b} 调用: -- 用()进行调用 -- 等价于 invoke() -- eg: sum(1,2) 或者 sum.invoke(1,2) 简化: -- 函数参数参数调用是最后一位 Lambda 可以移出去 -- 函数参数只有一个 Lambda ,调用时小括号可省略 -- Lambda 只有一个参数可默认为 it -- 入参、返回值与形参一直的函数可以用函数引用的方式作为实参传入
示例一下:
//首先 先看下Arrays里面的forEatch方法
public inline fun CharArray.forEach(action: (Char) -> Unit): Unit {
for (element in this) action(element)
}
-------------------------------------------------
接下来,代码中调用
---------------------------------------------------
val arrayOfChar: CharArray = charArrayOf('H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd')
//最基本的调用,传入action的代码块
arrayOfChar.forEach(char ->{println(char)})
// 简化
//1. Lambda只有一个参数可默认为it
arrayOfChar.forEach ({println(it)})
// 2. 函数参数参数调用是最后一位Lambda可以移出去
arrayOfChar.forEach(){pritln(it)}
// 3. 函数参数只有一个Lambda,调用时小括号可省略
arrayOfChar.forEach{pritln(it)}
// 4. 入参、返回值与形参一致的函数可以用函数引用的方式作为实参传入
arrayOfChar.forEach(::println)
复制代码
与 java 不同, kotlin 的操作符允许我们进行重载。重载的函数需要使用 operation 的修饰符标记 例子:
// 重写 减号的实例
class TestKotlin(var a:Int) {
operator fun minus(i:Int):Int{
return a - i
}
}
fun main() {
println(TestKotlin(6) - 5)
}
---------------------输入
1
复制代码
很多的操作符那些可以看一下 《Kotlin语言中文站》
infix 修饰的函数,使用时不需要 对象.方法名(参数) ,直接 对象 方法名 参数 //定义
class Book { infix fun on(palce:String){...}}
//使用
Book() on "My Name"
复制代码
for 循环的 in 把鼠标点击 in 可见其循环机制实际上是 iterator 机制, hasNext() 跟 next() ,判断有没有下一个值,有就获取
下面我们自己自定义一个 MyIterator ,跟 MyIntList 来演示一下
class MyIterator(val iterator:Iterator<Int>){
operator fun next():Int{
return iterator.next()
}
operator fun hasNext():Boolean{
return iterator.hasNext()
}
}
class MyIntList{
private val list = ArrayList<Int>()
fun add(int:Int){
list.add(int)
}
fun remove(int:Int){
list.remove(int)
}
operator fun iterator():MyIterator{
return MyIterator(list.iterator())
}
}
fun main() {
val list = MyIntList()
list.add(1)
list.add(2)
list.add(3)
for (i in list){
println(i)
}
}
复制代码
continue 跟
break ) 跟
java 一致,跳过当前循环用
continue ,终止循环用
break
3. 多层循环嵌套的终止结合标签使用
Outter@for(...){
Inner@while(i<0){if(...)break@Outter}
}
复制代码
可以定义标签,对应关键字后面加上@标签,代表跳出到对应的某一层, 举个例子:
fun main() {
val list = MyIntList()
list.add(1)
list.add(2)
list.add(3)
list.add(4)
list.add(5)
//break到上一层
for (i in list) {
print(" $i")
while (true) {
print(" $i")
break
}
}
println(" ")
//break到制定标签
OutSide@for (i in list) {
print(" $i")
while (true) {
print(" $i")
break@OutSide
}
}
}
---------------------打印---------------
1 1 2 2 3 3 4 4 5 5
1 1
复制代码
if else 分支表达式等与 java 的不同点,它们作为表达式,可以用来赋值,最后一个行的数据等于 return 的数据
fun compare():Int{
val i = 10
if (i == 10 ) 1 else 0
}
复制代码
与 java 不同的是,它也是表达式,最后一行的数据也是当成要返回的值。 但是 注意下面的写法:
return try{x/y}catch(e:Exception){0}finally{...}
复制代码
先执行完 try 有异常就跑到 catch ,最后 finally 的代码会执行,最后再返回值。(如果正常返回 0 ,抛异常就返回 x/y )
所有参数都有一点: 如果传参时有歧义,需要使用具名参数
fun sum(arg1:Int = 3,arg2:Int = 2) = arg1+arg2 复制代码
给函数的实参附上形参
fun sum(arg1:Int,arg2:Int) = arg1+arg2 sum(arg1=2,arg2=3) 复制代码
某个参数可以接受多个值 与 java 不同的是,它可以不用做最后一个参数, kotlin 支持具名函数,所以它可以放在参数中任意位置。
fun hello (vararg ints:Int,string:String){ ints.forEach(::println)}
使用:
hello(1,2,3,4,string="Hello")
复制代码
*变量名 ) 应用场景: 只支持展开Array,只用于变长参数列表的实参,不能重载,不是一定意义上的运算符
fun hello (double:Double,vararg ints:Int,string:String){ ints.forEach(::println)}
使用:
val array = intArrayOf(1,2,3,4)
hello(3.0,*array,string="Hello")
复制代码