Kotlin基础——变量、函数、字符串

变量

Kotlin和Java一样是静态语言,所有表达式类型在编译期已经确定

  • public 为默认可见性
  • internal 为模块可见性
  • private 修饰的类只能在当前文件中可用
  • protected 只允许类及子类使用,即使是同一文件内也不可使用

变量由 var/val+变量名[: 数据类型][?][ = 值] 组成,如

var a = 1

var b: Int
b = 3

var s: String? = null

val language = arrayListOf("java")
language.add("Kotlin")
  • 无需显式声明每个变量的类型,自动类型推导,但只有val才可自动类型转换,因为var无法保证类型后续不被修改
  • 若变量未初始化则需要显示指定类型
  • ?标记变量可以为空,若无则不可为空
  • val为不可变变量,初始化后不能再次赋值,对应Java的final,但其指向的对象可以改变

函数

函数组成为 fun 函数名(参数名: 参数类型, …): 返回值{}

fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

上面称为代码块函数体,当函数体由单个表达式构成时,可简化为表达式函数体(自动会推导出返回类型)

fun max(a: Int, b: Int) = if (a > b) a else b

默认参数和命名参数

如定义一个格式化输出集合的函数

fun <T> joinToString(
    collection: Collection<T>,
    separator: String,
    prefix: String,
    postfix: String
): String {
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()) {
        if (index > 0)
            result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}


val list = listOf("1", "2", "3")
println(joinToString(list, "-", "[", "]"))

在常规调用中,必须按照参数顺序给定参数,通过带默认值的参数可以省略后面的参数传递,默认参数被编码到被调用的函数内部

fun <T> joinToString(
    collection: Collection<T>,
    separator: String = "",
    prefix: String = "",
    postfix: String = ""
): String {
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()) {
        if (index > 0)
            result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}

println(joinToString(list, "-"))

Java需要显式传递所有参数,若需要调用上面的带默认参数的函数,需要用@JvmOverloads注解,会生成多个重载的Java函数

String joinToString(Collection<T> collection, String separator, String prefix, String postfix);
String joinToString(Collection<T> collection, String separator, String prefix);
String joinToString(Collection<T> collection, String separator);
String joinToString(Collection<T> collection);

如果使用命名参数可以省略中间的参数,按照任意顺序给定参数

println(joinToString(list, prefix = "[", postfix = "]"))

可变参数

由vararg定义,如下为listOf源码

public fun <T> listOf(vararg elements: T): List<T> = if (elements.size > 0) elements.asList() else emptyList()

可通过展开运算符*,把数组元素作为可变参数来调用

fun main(args: Array<String>) {
    val list = listOf("args1", *args)
    println(list)
}

中缀调用和解构声明

中缀调用为特殊的函数调用,如下是一个简单的to()函数定义,会生成一个Pair对象

infix fun Any.to(other: Any) = Pair(this, other)

使用的时候会自动解构声明

val (number, name) = 1 to "one"

println("$number")
println("$name")

在这里插入图片描述

map的生成和遍历使用到了中缀调用

val map = mapOf(1 to "one", 7 to "seven")

for ((number, name) in map) {
    println("$number:$name")
}

顶层函数和属性

如新建一个test.kt文件,创建max()方法,其不属于任何类

package com.demo.demo1

fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

会被编译TestKt.Java的静态函数

public class TestKt {
    public static int max(int a, int b) {
        if (a > b)
            return a;
        else
            return b;
    }
}

如果需要修改顶层函数生成的类的名称,可以在包名前添加注解,如下会变成MyTest.java

@file:JvmName("MyTest")

package com.demo.demo1

fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

同理,test.kt文件存放属性

package com.demo.demo1

var a = 0
val b = 1
const val c = 2

会被编译Java的静态域

public class TestKt {
    public static int a = 0;
    public static int b = 1;
    public static final int c = 2;
}

扩展函数

把要扩展的类/接口的名称放到即将添加的函数前面,如下扩展String类新增lastChar()方法

  • 可省略this
  • 能访问被扩展类的public方法和属性
  • 不在同一包的文件需要import扩展函数,若出现命名冲突,可以使用as重命名
  • 不能被子类重写
  • 如果扩展函数和成员函数有相同签名,会优先调用成员函数
  • 扩展函数本质上是静态函数(通过所在文件类名访问),但不能定义在类内部,会导致static消失,只能在类内或子类调用
fun String.lastChar(): Char = this.get(this.length - 1)

println("Kotlin".lastChar())

在Java中访问扩展函数(放在test.kt)

TestKt.lastChar("Kotlin");

需要注意的是扩展函数始终是静态调度的,如下使用父类指向子类,调用的扩展函数仍然是夫类的

open class Base
class Extended : Base()

fun Base.foo() = "Base"
fun Extended.foo() = "Extended"

val instance: Base = Extended()
val instance2: Extended = Extended()

println(instance.foo())
println(instance2.foo())

扩展属性

如下定义扩展属性,因为String内容不可变,所以没有setter()

val String.lastChar: Char
    get() = this.get(length - 1)

var java.lang.StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value: Char) {
        setCharAt(length - 1, value)
    }

当Java中访问扩展属性(放在test.kt),需要显式调用getter()

TestKt.getLastChar("Java");

局部函数

如下类,在存储时需要验证各个字段的有效性

class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
    if (user.name.isEmpty()) {
        throw IllegalArgumentException("can't save user ${user.id} : empty name")
    }

    if (user.address.isEmpty()) {
        throw IllegalArgumentException("can't save user ${user.address} : empty address")
    }
}

局部函数可使用可使用外层函数的参数,如下抽取为通用的验证方法

class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
    fun validate(value: String, field: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException("can't save user ${user.id} : empty $field")
        }
    }
    validate(user.name, "name")
    validate(user.address, "address")
}

若User和saveUser为系统的对象,我们不能对其原方法改动,可将其作为扩展函数

class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
    //原生方法
}

fun User.validateBeforeSave(value: String, field: String) {
    if (value.isEmpty()) {
        throw IllegalArgumentException("can't save user ${id} : empty $field")
    }
}

fun MySaveUser(user: User) {
    user.validateBeforeSave(user.name, "name")
    user.validateBeforeSave(user.address, "address")
    saveUser(user)
}

字符串

字符串模板

可在字符串中通过$引用变量

fun main(args: Array<String>) {
    val name = if (args.size > 0) args[0] else "Kotlin"
    println("Hello,$name")
}

还可以用${}引用表达式

fun main(args: Array<String>) {
    if (args.size > 0) {
        println("Hello,${args[1]}")
    }
}

fun main(args: Array<String>) {
    println("Hello,${if (args.size > 0) args[0] else "Kotlin"} ")
}

正则表达式

如下Java代码返回null,因为split()接收的是一个正则表达式,点会被作为任意字符

String s = "12.34";
System.out.println(Arrays.toString(s.split(".")));

而在Kotlin中,可显式声明正则

val s = "12.34"
println(s.split("\\.".toRegex()))

三重引号

三重引号可避免转义字符

println("""C:\\Users\\User\\Desktop""")

还可以处理前缀及其前面的空格(默认为|),如下用.当前缀,

println(""".A
            .B
            .   C
        """.trimMargin("."))

上面输出

A
B
   C
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值