Kotlin 基础学习

学!

原文: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循环

有许多很好用的新函数
比如:
范围 rangeTo1…100 代表1到100
步长 step1…100 step 2 代表1,3,5,7…97,99
降序 downTo100 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
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值