kotlin 入门中文教程(1)

平台类型是 kotlin 对 java 所作的一种平衡性设计。kotlin 将对象的类型分为了可空类型和不可空类型两种,但 java 平台的一切对象类型均为可空的,当在 kotlin 中引用 java 变量时,如果将所有变量均归为可空类型,最终将多出许多 null 检查;如果均看成不可空类型,那么就很容易就写出忽略了NPE 风险的代码。为了平衡两者,kotlin 引入了平台类型,即当在 kotlin 中引用 java 变量值时,既可以将之看成可空类型,也可以将之看成不可空类型,由开发者自己来决定是否进行 null 检查

九、类型的检查与转换

9.1、类型检查

is 与 !is 操作符用于在运行时检查对象是否符合给定类型:

fun main() {
val strValue = “leavesC”
parserType(strValue) //value is String , length : 7
val intValue = 100
parserType(intValue) //value is Int , toLong : 100
val doubleValue = 100.22
parserType(doubleValue) //value !is Long
val longValue = 200L
parserType(longValue) //unknown
}

fun parserType(value: Any) {
when (value) {
is String -> println(“value is String , length : ${value.length}”)
is Int -> println(“value is Int , toLong : ${value.toLong()}”)
!is Long -> println(“value !is Long”)
else -> println(“unknown”)
}
}

9.2、智能转换

在许多情况下,不需要在 kotlin 中使用显式转换操作符,因为编译器跟踪不可变值的 is 检查以及显式转换,并在需要时自动插入安全的转换

例如,对于以下例子来说,当判断 value 为 String 类型通过时,就可以直接将 value 当做 String 类型变量并调用其内部属性

fun main() {
val strValue = “leavesC”
parserType(strValue) //value is String , length : 7

val intValue = 100
parserType(intValue) //value is Int , toLong : 100

val doubleValue = 100.22
parserType(doubleValue) //value !is Long

val longValue = 200L
parserType(longValue) //unknown
}

fun parserType(value: Any) {
when (value) {
is String -> println(“value is String , length : ${value.length}”)
is Int -> println(“value is Int , toLong : ${value.toLong()}”)
!is Long -> println(“value !is Long”)
else -> println(“unknown”)
}
}

编译器会指定根据上下文环境,将变量智能转换为合适的类型

if (value !is String) return
//如果 value 非 String 类型时直接被 return 了,所以此处可以直接访问其 length 属性
println(value.length)

// || 右侧的 value 被自动隐式转换为字符串,所以可以直接访问其 length 属性
if (value !is String || value.length > 0) {

}

// && 右侧的 value 被自动隐式转换为字符串,所以可以直接访问其 length 属性
if (value is String && value.length > 0) {

}

9.3、不安全的转换操作符

如果转换是不可能的,转换操作符 as 会抛出一个异常。因此,我们称之为不安全的转换操作符

fun main() {
parserType(“leavesC”) //value is String , length is 7
parserType(10) //会抛出异常 ClassCastException
}

fun parserType(value: Any) {
val tempValue = value as String
println(“value is String , length is ${tempValue.length}”)
}

需要注意的是,null 不能转换为 String 变量,因为该类型不是可空的

因此如下转换会抛出异常

val x = null
val y: String = x as String //会抛出异常 TypeCastException

为了匹配安全,可以转换的类型声明为可空类型

val x = null
val y: String? = x as String?

9.4、安全的转换操作符

可以使用安全转换操作符 as? 来避免在转换时抛出异常,它在失败时返回 null

val x = null
val y: String? = x as? String

尽管以上例子 as? 的右边是一个非空类型的 String,但是其转换的结果是可空的

十、类

10.1、基本概念

类的概念就是把数据和处理数据的代码封装成一个单一的实体。在 Java 中,数据存储在一个私有字段中,通过提供访问器方法:getter 和 setter 来访问或者修改数据

在 Java 中以下的示例代码是很常见的,Point 类包含很多重复的代码:通过构造函数把参数赋值给有着相同名称的字段,通过 getter 来获取属性值

public final class Point {

private final int x;

private final int y;

public Point(int x, int y) {
this.x = x;
this.y = y;
}

public final int getX() {
return this.x;
}

public final int getY() {
return this.y;
}

}

使用 kotlin 来声明 Point 类则只需要一行代码,两者完全等同

class Point(val x: Int, val y: Int)

kotlin 也使用关键字 class 来声明类,类声明由类名、类头(指定其类型参数、主构造函数等)以及由花括号包围的类体构成,类头与类体都是可选的,如果一个类没有类体,可以省略花括号。此外,kotlin 中类默认是 publish(公有的) 且 final (不可继承)的

kotlin 区分了主构造方法(在类体外部声明)和次构造方法(在类体内部声明),一个类可以有一个主构造函数和多个次构造函数,此外也允许在初始化代码块中 init 添加额外的初始化逻辑

10.2、主构造函数

主构造函数是类头的一部分,跟在类名(和可选的类型参数)后,主构造函数的参数可以是可变的(var)或只读的(val)

class Point constructor(val x: Int, val y: Int) {

}

如果主构造函数没有任何注解或者可见性修饰符,可以省略 constructor 关键字

class Point(val x: Int, val y: Int) {

}

//如果不包含类体,则可以省略花括号
class Point(val x: Int, val y: Int)

如果构造函数有注解或可见性修饰符,则 constructor 关键字是必需的,并且这些修饰符在它前面

class Point public @Inject constructor(val x: Int, val y: Int) {

}

主构造函数不能包含任何的代码,初始化的代码可以放到以 init 关键字作为前缀的初始化块(initializer blocks)中,初始化块包含了在类被创建时执行的代码,主构造函数的参数可以在初始化块中使用。如果需要的话,也可以在一个类中声明多个初始化语句块。需要注意的是,构造函数的参数如果用 val/var 进行修饰,则相当于在类内部声明了一个同名的全局属性。如果不加 val/var 进行修饰,则构造函数只能在 init 函数块和全局属性初始化时进行引用

此外,要创建一个类的实例不需要使用 Java 中的 new 关键字,像普通函数一样调用构造函数即可

class Point(val x: Int, val y: Int) {

init {
println(“initializer blocks , x value is: $x , y value is: $y”)
}

}

fun main() {
Point(1, 2) // initializer blocks , x value is: 1 , y value is: 2
}

主构造函数的参数也可以在类体内声明的属性初始化器中使用

class Point(val x: Int, val y: Int) {

private val localX = x + 1

private val localY = y + 1

init {
println(“initializer blocks , x value is: $x , y value is: $y”)
println(“initializer blocks , localX value is: $localX , localY value is: $localY”)
}

}

fun main() {
Point(1, 2)
//initializer blocks , x value is: 1 ,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值