学!
原文:https://blog.csdn.net/CrazyApes/article/details/122091459
文章目录
Kotlin
只要学,啥时候都不晚!
这里主要介绍从java转到kotlin中一些常见的基础学习
读完这篇文章
你应该能很快适应kotlin的开发节奏了
内容不断补充中…
点击标题头可以直达文档,因为本文只简介,想了解更详细具体内容的可以直接看原文档
线上编写
Kotlin官网提供了 PlayGround 供大家线上尝试
地址:https://play.kotlinlang.org/
哈哈,没有环境的小伙伴或者只是想尝试的小伙伴,可以使用线上编写。
比如,我写博客的很多东西其实都是在线上试的,哈哈。
变量
弱数据类型
- var 可变变量
- val 只读变量 类似final
// 各种示例
var name = "CrazyApes"
name = "CrazyApe"
var myName : String = "CrazyApes"
var age : Int = 99
var number = 3.1
var floatNumber
val value = "不可变"
class Address {
var name: String = "Holmes, Sherlock"
var street: String = "Baker"
var city: String = "London"
var state: String? = null
var zip: String = "123456"
}
lateinit延迟初始化
需要在特定时期初始化的字段可以用 lateinit 声明
- 必须初始化后才可以使用,否则会出异常
kotlin.UninitializedPropertyAccessException: lateinit property value has not been initialized - lateinit 声明后不允许赋值为 null, 加问号也不行。
所以,如以下示例代码,findViewById返回为null会崩,当然,我们本意也不希望它空,但是这个是要注意你如果声明的是一些需要用的变量的话 ,需要注意此类问题。
private lateinit var mBaseView : View
private lateinit var mData : String
private var mNullableStr : String? = null
// 例如 onCreate
onCreate(...){
mBaseView = findViewById(R.id.baseView)
// 未初始化 UninitializedPropertyAccessException
print(mData)
// 可检查
if (mData.isInitialized)
print(mData)
// 如果return了null 就 NullPointerException
mData = getIntent.getExtraString("MaybeNull")
mNullableStr = getIntent.getExtraString("MaybeNull")
val length = mNullableStr?.length // 如果null ,return null
val length1 = mNullableStr?.length ?: -1; // 如果null ,return -1 有点像三目的感觉
}
空安全
kotlin 是空安全的语言
意思就是你要是没显示声明可以为空,只要遇到了空就报空指针。
- ?. 安全的调用方式
如果是 null 不会执行后续的操作,直接返回 null - ?:
如果是 null,则执行冒号后面的部分 - !!
非空断言运算符,若果是null,就NullPointerException
private var mNullableStr : String? = null
private var mNullableList : List<Int?> ?= null
fun testForNullSafe(){
mNullableStr = getIntent.getExtraString("MaybeNull")
val length = mNullableStr?.length // 如果null ,return null
val length1 = mNullableStr?.length ?: -1; // 如果null ,return -1 有点像三目的感觉
val length2 = mNullableStr!!.length; // 如果null ,就 NullPointerException
mNullableList = listOf(1, 2, null, 4)
}
比较==,===,equals
- == 结构值相等
类似Java中equals - === 和 !== 内存引用相等和不等
类似Java中原来的 == 和 !=
注意:
1.如果是基类略等于==,比如Int啥的
2. Float 和 Double 比较特殊。
某些特殊情况下,比如,如果当操作数不是静态类型化为浮点数,调用的就会是对应的equals方法和compareTo方法,会导致以下结果出现。
a). -0.0 比 0.0小。
b). NaN被认为与自身相等。
c). NaN比无穷大都大。
大家可以通过以下代码验证其结果性。
// 静态化浮点数
print(-0.0f == 0.0f) // true
print(Float.NaN == Float.NaN) // false
print(Float.NaN > Float.POSITIVE_INFINITY) // false
// 非静态化为浮点数 例如 :Any
val numZero1 : Any = -0.0f
val numZero2 : Any = 0.0f
println(numZero1 == numZero2) // false 通过 equals 比较
// Comparable
val numZero3 : Comparable<Float> = -0.0f
val numZero4 : Float = 0.0f
println(numZero1 < numZero2) // true 通过 compareTo 比较
// NaN
val firstNaN : Any = Float.NaN
val secondNaN = Float.NaN
println(firstNaN == secondNaN) // true 通过 equals 比较
// 无穷
val compareNaN : Comparable<Float> = Float.NaN
val positiveInfinity = Float.POSITIVE_INFINITY // 正无穷
println(compareNaN > positiveInfinity) // true 通过 compareTo 比较
- equals
理解为用于自定义的比较,重写equals方法,不影响==的比较性
for循环
有许多很好用的新函数
比如:
范围 rangeTo : 1…100 代表1到100
步长 step : 1…100 step 2 代表1,3,5,7…97,99
降序 downTo: 100 downTo 1 代表 100,99,98…1 ,其实就是步长为-1
还有很多,直接看例子吧。
fun main() {
for (i in 1..100) // 遍历 1 到 100
println(i) // 1,2,3,4,5,... 99,100
for (i in 100 downTo 1) // 遍历 100 到 1
println(i) // 100,99,98...2,1
for (i in 100 downTo 1 step 2) // 遍历 100 到 1 步长为 2
println(i) // 100,98,96....2
for (i in 1 until 100) // 遍历 1 到 100 [1,100) 不包括100
println(i) // 1,2,3,4 ... 98,99
val arr = arrayOf("a", "b", "c", "d", "e")
for (item in arr) // 遍历数组
println(item) // a,b,c,d,e
for (i in arr.indices) // 遍历下标
println(i) // 0,1,2,3,4
for ((index, value) in arr.withIndex()) // 获取下标及值
println("the element at $index is $value") // ... 0 is a,... 1 is b,... 2 is c
arr.reverse() // 反转数组
for (item in arr) // 遍历反转后的数组
println(item) // e,d,c,b,a
}
when
可以替代 switch 和 各种 if…else 语句
val str = when (index) {
0 -> "Empty"
in 1..9 -> "Number"
in 10..100 -> "under 100"
else -> "Other"
}
when {
index == 0 -> a + b
index in 1..9 -> a - b
index is Number -> a = b
index is String -> a = 0
index == "3" -> a = 3
else -> a / b
}
val num = (1..999).random() // 随机产生 1-999中的任何一个
val numStr = when (num) {
in 1..9 -> "00$num" // 001,002,003...009
in 10..99 -> "0$num" // 010,011,012...099
else -> "$num" // 100...999
}
println(numStr)
三目运算
Kotlin没有标准的三目运算符,所以都换成 if…else 了
搭配Lambda之后发现也没啥区别了。
甚至还更灵活了。
复杂一些的可以直接考虑用 when
fun main() {
val a = 1
val temp = if (a == 1) 2 else a
println(temp) // temp = 2
// view
view.visibility = if (view.visibility == View.VISIBLE) View.GONE else View.VISIBLE
}
DataClasses
数据类
大概类似于vo
bean
pojo
等数据类
注意事项
-
主构造函数必须要至少有一个参数
在Java虚拟机里,如果生成的类需要有一个无参数的构造函数,所有属性的默认值必须有一个具体的值 -
主构造函数中的所有参数必须被标记为val或者var
-
数据类不能有以下修饰符:abstract,inner,open,sealed
// 常见方式
data class NetData(
val state: Int,
val data: Data
) {
// 等同于java静态内部类 static class
// kotlin 内部类需 加 inner 标识
// 没加inner 就是静态内部类
data class Data(
val name: String,
val age: Int,
val sex: Int
)
}
// 需要无参构造的事例
data class User(val name: String = "",
val age: Int = 0)
静态内部类实现
kotlin 有专门的 inner 标识非静态内部类
没有添加 inner 标识则默认为静态内部类使用
data class NetData(
val state: Int,
val data: Data
) {
// 等同于java静态内部类 static class
// kotlin 内部类需 加 inner 标识
// 没加inner 就是静态内部类
class Data(
val name: String,
val age: Int,
val sex: Int
)
}
扩展属性
扩展属性是个好东西啊。
比如我可以快速的转换dp,或者sp操作等
/**
* 扩展属性,dp
* dp to px
*/
val Number.dp: Float
get() = android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_DIP,
this.toFloat(),
Resources.getSystem().displayMetrics
)
/**
* 扩展属性,sp
* sp to px
*/
val Number.sp: Float
get() = android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_SP,
this.toFloat(),
Resources.getSystem().displayMetrics
)
fun main() {
// 3 dp to px
println(3.dp) // print Float
println(3.dp.toInt) // print Int
}
Java调用顶级函数
可以使用 @file:JvmName(JavaName)
标注
// DemoTempUtil.kt
@file:JvmName("TempUtil")
package com.crazy.demo.temp
fun DemoActivity.demoFuntion(title:String):Boolean {
return title == "demo"
}
// Java DemoActivity
private void checkTitle() {
TempUtil.demoFuntion(this,title);
}
synchroized
kotlin 没有 synchroized 关键字
- 同步方法
但是可以使用@Synchronized
注解。
这个注解和Java中的synchronized有同样的效果:它将把JVM方法标记为同步。
@Synchronized fun synchronizedMethod() {
println("synchronized method:${Thread.currentThread()}")
}
- 同步代码块
此外,kotlin还有自己的synchronized()
方法用来锁定代码块。
fun synchronizedBlock() {
synchronized(lock){
println("synchronized block")
}
}
可以看一下源码实现
( kotlin version : 1.6.0 )
@file:kotlin.jvm.JvmMultifileClass
@file:kotlin.jvm.JvmName("StandardKt")
package kotlin
import kotlin.contracts.*
import kotlin.jvm.internal.unsafe.*
/**
* Executes the given function [block] while holding the monitor of the given object [lock].
*/
@kotlin.internal.InlineOnly
public inline fun <R> synchronized(lock: Any, block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE", "INVISIBLE_MEMBER")
monitorEnter(lock)
try {
return block()
}
finally {
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE", "INVISIBLE_MEMBER")
monitorExit(lock)
}
}
volatile
同样的,kotlin 也没有 volatile 关键字
同样可以使用注解 @volatile
的方式使用。
@Volatile private var running = false
wait,notify 与 notifyAll
在kotlin里面,每一个类都是从 Any
继承过来的,但是 Any
并没有声明wait()
,notify()
和notifyAll()
方法。
但是你能用 java.lang.Object
的实例作为 lock
,并且调用相关的方法。
private val lock = java.lang.Object()
fun produce() = synchronized(lock) {
while (items >= maxItems) {
lock.wait()
}
Thread.sleep(rand.nextInt(100).toLong())
items++
println("Produced, count is $items: ${Thread.currentThread()}")
lock.notifyAll()
}
fun consume() = synchronized(lock) {
while (items <= 0) {
lock.wait()
}
Thread.sleep(rand.nextInt(100).toLong())
items--
println("Consumed, count is $items: ${Thread.currentThread()}")
lock.notifyAll()
}
thread
kotlin 有封装好的 thread
方法
// 方法一
// kotlin 方法
thread(start=true) {
println("running from thread():${Thread.currentThread()}")
}
// 方法二
object : Thread() {
override fun run() {
println("running from Thread: ${Thread.currentThread()}")
}
}.start()
// 方法三
Thread({
println("running from lambda: ${Thread.currentThread()}")
}).start()
这里仅贴一下源码。方便大家查看
@file:JvmName("ThreadsKt")
package kotlin.concurrent
/**
* Creates a thread that runs the specified [block] of code.
*
* @param start if `true`, the thread is immediately started.
* @param isDaemon if `true`, the thread is created as a daemon thread. The Java Virtual Machine exits when
* the only threads running are all daemon threads.
* @param contextClassLoader the class loader to use for loading classes and resources in this thread.
* @param name the name of the thread.
* @param priority the priority of the thread.
*/
public fun thread(
start: Boolean = true,
isDaemon: Boolean = false,
contextClassLoader: ClassLoader? = null,
name: String? = null,
priority: Int = -1,
block: () -> Unit
): Thread {
val thread = object : Thread() {
public override fun run() {
block()
}
}
if (isDaemon)
thread.isDaemon = true
if (priority > 0)
thread.priority = priority
if (name != null)
thread.name = name
if (contextClassLoader != null)
thread.contextClassLoader = contextClassLoader
if (start)
thread.start()
return thread
}