Java类型系统
Kotlin类型系统
- 上面两个图 对比之后,会发现Kotlin中全是包装类型,原始类型哪里去了?
- Kotlin只有包装类型,在编译器编译代码的时候,自动优化性能,把对应的包装类型拆箱为原始类型
装箱和拆箱
- 在Java中,从基本数字类型到引用数字类型的转换过程就是典型的装箱操作,反过来就是拆箱操作。
- 在Kotlin中非空数字类型到Int到可空数字类型Int?需要进行装箱操作,同时,非空的Int?类型会被编译器自动拆箱成基本数据类型Int
- 注意
- Jav和Kotlin在装箱和拆箱放面在范围是 [-128, 127] 之间的数装箱时并不会创建新的对象,所以这里a1和a2装箱后的对象是同一个,a1 === a2也就返回true了。这里改为128或-129就又会变成false了。
- 接下来看几个示例
// a, b都是原始数据类型
@Test
fun test04() {
val a: Int = 1000
val b: Int = 1000
println(a === b) //true
print(a == b) //true
}
// 装箱和拆箱时不会创建新的对象
@Test
fun test04() {
val a: Int? = 10
val b: Int? = 10
println(a === b) //true
print(a == b) //true
}
// 装箱和拆箱时创建了新的对象
@Test
fun test04() {
val a: Int? = 1000
val b: Int? = 1000
println(a === b) //false
print(a == b) // true
}
Kotlin中数字类型和Java中数字类型对应
Kotlin | Java |
Int | int |
Long | long |
Float | float |
Double | double |
Int? | Integer |
Long? | Long |
Float? | Float |
Double? | Double |
BooleanArray | boolean[] |
ByteArray | byte[] |
CharArray | char[] |
DoubleArray | double[] |
FloatArray | float[] |
IntArray | int[] |
LongArray | long[] |
ShortArray | short[] |
可空类型
- 在Java8中使用Optional来表达可空的类型
Optional.ofNullable(null);
- 在Kotlin中使用“类型?”实现了Optional的意义
fun strLength(s :String?) : Int {
return s?.length ? : 0
}
安全操作符
安全调用符 “ ?”
- Kotlin在 我们进行声明的时候就可以直接将其设置为是否为空,这时候就要用到安全调用符“?”同时可能为空的对象未使用安全调用符直接进行调用在编译时就会报错
val str : String = null // 编译不通过,不可空的String不可以赋值为null
val str : String? = null //正确写法
@Test
fun test05() {
var nullableStr : String? = null
println(nullableStr?.length) // null
nullableStr = "abc"
println(nullableStr?.length) // 3
}
非空断言“ !! "
- 非空断言使得可空类型对象可以调用成员方法或者属性,当对象为空时抛出空指针异常
@Test
fun test06() {
var nullableStr : String? = null
println(nullableStr!!.length) // kotlin.KotlinNullPointerException
}
特殊类型
Unit类型
- Kotlin中的Unit类型相当于Java中的void类型
- 一般不需要显示声明,编译器会自行进行推断
- Kotlin.Unit父类型时Any, 如果是一个可空的Unit那么父类型就是Any?
@Test
fun example() {
println("hello")
}
val exampleResult = example()
println(exampleResult) // hello kotlin.Unit
@Test
fun test07() {
val return1 = unitReturn1()
println(return1)
val return2 = unitReturn2()
print(return2)
}
fun unitReturn1() {
// 空函数体,返回类型时Unit
}
fun unitReturn2() :Unit {
// 显式声明返回类型Unit
return Unit;
}
- Unit类型层次结构图
Nothing 和Nothing?类型
- Java中的Void对应Kotlin中的Nothing?,唯一可被访问的返回值为null
- Nothing类型的结构层次图
- Nothing主构造函数是私有的,不能实例化,可以使用Nothing来表达一个不存在的返回值
- Nothing和Unit区别
- Nothing代表没有返回值,即计算结果不会返回
- Unit计算结果返回为空,为Unit类型
- Nothing?唯一允许的值是null, 可被用作任何可空类型的空引用
Any和Any
- Any是非空类型层次结构的根,Any?是可空类型层次的根, Any?是Any的超集,Any?是Kotlin类型层次结构的最顶端
@Test
fun testAny() {
println(1 is Any) // true
println(1 is Any?) // true
println(null is Any) // false
println(null is Any?) // true
println(Any() is Any?) // true
}
类型检测和类型转换
类型检测
- is 运算符可以检查对象A是否与特定的类型B兼容( 此对象A是B类型或者派生于B类型),还可以用来检查一个对象(变量)是否属于某数据类型(如Int String Boolean 等)
- 类似于Java中的instanceof
@Test
fun test08() {
println("abc" is String) // true
println(null is Any) // false
}
@Test
fun test08() {
val father = Father()
val son = Son()
val sonMult : Father = son
println(father is Father) // true
println(son is Son) // true
println(sonMult is Father) // true
println(sonMult is Son) // true
}
类型自动转换
- 在Kotlin中不需要显示的类型强制转换, 因为编译器会跟踪不可变值的is(类型检查),并在需要时自动转换
@Test
fun test09() {
val string :Any = 10
if (string is String) {
println(string.length)
} else if (string is Boolean) {
println(true)
} else if (string is Int) {
println(string + 10)
}
}
as运算符
- as 运算符用于执行引用类型的显式类型转换。 如果要转换的类型与指定的类型兼容, 转换就会成功进行,如果类型不兼容,使用 as ?运算符就会返回 null
@Test
fun test10() {
val father = Father()
val son = Son()
val sonMult : Father = Son()
println(father as Son) // as? =>null as=>java.lang.ClassCastExceptio
println(sonMult as? Son) // 可以转换
println(father as? Father) // 可以转换
}