Android JAVA转Kotlin速成

前言

由于项目需要现在需要从JAVA转到Kotlin,记录一下学习过程。教材《疯狂Android讲义kotlin》。本篇不会介绍Android基础知识,着重讲解Java到Kotlin代码的变化。

在线编译网站:https://c.runoob.com/compile/2960/。一般我都是在Android Studio上面写,然后网站上面运行。

类的修饰符。

类的修饰符包括 classModifier 和_accessModifier_:

  • classModifier: 类属性修饰符,标示类本身特性。

    abstract    // 抽象类  
    final       // 类不可继承,默认属性
    enum        // 枚举类
    open        // 类可继承,类默认是final的
    annotation  // 注解类
  • accessModifier: 访问权限修饰符

    private    // 仅在同一个文件中可见
    protected  // 同一个文件中或子类可见
    public     // 所有调用的地方都可见
    internal   // 同一个模块中可见

类定义

Java:

public class MainActivity extends AppCompatActivity {

Kotlin:

class MainActivity : AppCompatActivity() {

可以看到,继承变成了一个符号‘:’,并且可以省略权限修饰符。

属性定义

class Runoob {
    var name: String = ……
    var url: String = ……
    var city: String = ……
}

getter,setter

lass Person {

    var lastName: String = "zhang"
        get() = field.toUpperCase()   // 将变量赋值后转换为大写
        set

    var no: Int = 100
        get() = field                // 后端变量
        set(value) {
            if (value < 10) {       // 如果传入的值小于 10 返回该值
                field = value
            } else {
                field = -1         // 如果传入的值大于等于 10 返回 -1
            }
        }

    var heiht: Float = 145.4f
        private set
}

主构造器

写在class旁边,用init初始化。

class Person constructor(firstName: String) {
    init {
        println("FirstName is $firstName")
    }
}

如果构造器有注解,或者有可见度修饰符,这时constructor关键字是必须的,注解和修饰符要放在它之前。

class People(val firstName: String, val lastName: String) {
    //...
}

次构造器

写法同方法一致

class Person { 
    constructor(parent: Person) {
        parent.children.add(this) 
    }
}

方法与重写

Java:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);

Kotlin:

override fun onCreate(savedInstanceState: Bundle?) : Unit {
    super.onCreate(savedInstanceState)

可以看到,override的注解变成了修饰符。

返回值位置不再写类型,返回值类型写在方法之后。

参数需要写类型。并且语句后不再有;。

参数名称写:左边,类型写:右边。

参数类型后面的?,表示为空返回null。

继承

Kotlin所有类都继承自Any

可变长参数函数

fun vars(vararg v:Int){
    for(vt in v){
        print(vt)
    }
}

// 测试
fun main(args: Array<String>) {
    vars(1,2,3,4,5)  // 输出12345
}

常量与变量

val a: Int = 1
val b = 1
val c : Int
c = 1
var x = 5
x+=1

字符串

$varName 表示变量值

${varName.fun()} 表示变量的方法返回值

var a = 1
// 模板中的简单名称:
val s1 = "a is $a" 

a = 2
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"

空指针检查机制

?、!!、?:

//类型后面加?表示可为空
var age: String? = "23" 
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1

用法

fun parseInt(str: String): Int? {
    return str.toIntOrNull()
}

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)

    // 直接使用 `x * y` 会导致错误, 因为它们可能为 null
    if (x != null && y != null) {
        // 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量
        println(x * y)
    }
    else {
        println("'$arg1' or '$arg2' is not a number")
    }    
}

fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("a", "b")
}
fun parseInt(str: String): Int? {
    return str.toIntOrNull()
}

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)
    
    // ...
    if (x == null) {
        println("Wrong number format in arg1: '$arg1'")
        return
    }
    if (y == null) {
        println("Wrong number format in arg2: '$arg2'")
        return
    }

    // 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量
    println(x * y)
}

fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("99", "b")
}

类型检测与自动转换

fun getStringLength(obj: Any): Int? {
  if (obj is String) {
    // 做过类型判断以后,obj会被系统自动转换为String类型
    return obj.length 
  }

  //在这里还有一种方法,与Java中instanceof不同,使用!is
  // if (obj !is String){
  //   // XXX
  // }

  // 这里的obj仍然是Any类型的引用
  return null
}

区间

fun main(args: Array<String>) {
    print("循环输出:")
    for (i in 1..4) print(i) // 输出“1234”,4..1则不输出
    println("\n----------------")
    print("设置步长:")
    for (i in 1..4 step 2) print(i) // 输出“13”
    println("\n----------------")
    print("使用 downTo:")
    for (i in 4 downTo 1 step 2) print(i) // 输出“42”
    println("\n----------------")
    print("使用 until:")
    // 使用 until 函数排除结束元素
    for (i in 1 until 4) {   // i in [1, 4) 排除了 4
        print(i)
    }
    println("\n----------------")
}

比较

===比较地址,==比较数值。Kotlin没有基本数据类型,每个变量都有一个对象。

fun main(args: Array<String>) {
    val a: Int = 10000
    println(a === a) // true,值相等,对象地址相等

    //经过了装箱,创建了两个不同的对象
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    //虽然经过了装箱,但是值是相等的,都是10000
    println(boxedA === anotherBoxedA) //  false,值相等,对象地址不一样
    println(boxedA == anotherBoxedA) // true,值相等
}

类型转换

类型转换必须通过方法.toType()实现,较小类型不再是较大类型的子类型。有时候也会自动类型转换,比如long+int

toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char

位运算

shl(bits) – 左移位 (Java’s <<)
shr(bits) – 右移位 (Java’s >>)
ushr(bits) – 无符号右移位 (Java’s >>>)
and(bits) – 与
or(bits) – 或
xor(bits) – 异或
inv() – 反向

字符

char不能与数字直接操作,必须用单引号包含起来

数组

fun main(args: Array<String>) {
    //[1,2,3]
    val a = arrayOf(1, 2, 3)
    //[0,2,4]
    val b = Array(3, { i -> (i * 2) })

    //读取数组内容
    println(a[0])    // 输出结果:1
    println(b[1])    // 输出结果:2
}

字符串

for (c in str) {
    println(c)
}

字符串模板

字符串可以包含模板表达式,用$开头。

fun main(args: Array<String>) {
    val s = "runoob"
    val str = "$s.length is ${s.length}" // 求值结果为 "runoob.length is 6"
    println(str)
}

when

类似switch,格式为

when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}
when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}
fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}
when {
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
}

Lambda

如何理解Lambda,Lambda可以理解为一个对象,但是这个对象比较特殊,以一段代码的方式呈现。

比如 {x:Int,y:Int->x+y},->左边的为参数,右边的为函数体。

let、run、with、also、apply

这些函数叫做标准域函数,也叫拓展函数,主要是为了简化一些操作

函数 参数个数 内部访问上下文对象 返回值
let 1 it lambda最后一行代码返回值
with 2 this 或者 省略 lambda最后一行代码返回值
run 1 this 或者 省略 lambda最后一行代码返回值
apply 1 this 或者 省略 返回调用者对象
also 1 it 返回调用者对象  

首先我们来看一个类。

data class Book(var name: String, var author: String, var price: String){
  fun adjust( value: Int){
    price = price.plus(value)
  }
}
fun main(){
}

然后用let去调用他,it表示参数,参数即是原方法返回值。拓展函数返回值默认为let最后一行,下面println返回unit类型,也就是java的void。

Book("《海边的卡夫卡》", "村上春树", 59)
            .let {
                println(it)
                it.adjust(-5)
                it  			//因为adjust()方法没有返回值,我们需要将调整价格后的Book对象作为lamda表达式的返回值返回
            }
            .let {
                println(it)
            }

用also去调用他,it表示参数,参数即是原方法返回值。拓展函数返回值默认为this,即Book。

        Book("《海边的卡夫卡》", "村上春树", 59)
            .also {
                println(it)
                it.adjust(-5)			// 由于also直接返回当前对象,所以我们不用再提供返回值
            }
            .let {
                println(it)
            }

to、or、and

to用于key-value,在中间充当衔接作用,比如 key to value。

or为或位运算

and为且位运算

inline noinline crossinline

inline:通过内联(函数内容直插到调用处)的方式来编译函数,推荐高阶函数使用inline进行优化

noinline:局部关掉这个优化,来摆脱(不能把函数类型的参数当对象使用的使用)限制。

crossinline:让内联函数里的函数类型的参数可以被间接调用,代价是不能在Lambda表达式里使用return(return@label 这种形式还是可以的)

高阶函数

posted @   Miraculous_B  阅读(965)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示