说在前面
从上一篇我们了解了 kotlin 这门语言,以及通过 IntelliJ IDEA 和 AndroidStudio 开发工具创建了 kotlin 项目并运行了 “hello world” 程序,在这一篇,我们将来学习 kotlin的数据类型系统,以及各种类型之间的转换。
1. Java 类型系统
由上图可知:在 Java 中,类型系统由8种基本类型,6种引用类型以及一种空特殊的空引用类型。
基本类型:byte,char,short,long,float,double,int,boolean
-
引用类型:
类:class
接口:interface
数组:array
参数化类型:泛型
注解:Annotation
枚举:enumeration
空引用:null
基本数据类型和引用数据类型在创建的时候,内存的存储方式区别:
基本数据类型:在被创建时,在栈上给其划分一块内存,将数值 直接存储在栈上(性能高);
引用数据类型:在被创建时,首先在栈上给其引用(句柄)分配 一块内存,而对象的具体信息存储在堆内存上,然后由栈上面 的引用指向堆中对象的地址。
2.kotlin 类型系统
在 kotlin 中,将类型系统根据数据是否可空分为了可空类型和不可空类型。可空类型能够在编译程序的时候进行类型检查,以提前发现并解决问题,大大的降低了出现空指针的情况。
2.1 不可空类型
kotlin 中不可空的数字类型对应了 Java 中的原始类型,但是写法却 不一样:
- Kotlin中的数字类型与 Java 原始的数字类型
// 声明Int 型
val age:Int=20
//声明Long 型
val along:Long=12368172397127391
//声明 Float 型
val aFloat:Float=2.0F
//声明 double 型
val aDouble:Double=3.0
//声明 Short 型
val aShort:Short=127
// 声明Byte 型
val maxByte: Byte = Byte.MAX_VALUE
//声明Boolean
val aBoolean: Boolean = true
以上都是不可空的数字类型,在声明变量的时候都给它们赋了值,但是如果我们不给它赋值或者赋值为空,则编译器会显示错误,提醒我们必须要初始化该数字类型的值。
-
Kotlin中可空数字类型与 Java 中装箱数字类型
2.2 可空类型
在Java 开发中,经常会遇到空指针的问题,那么能不能在编译的时候提前发现错误并进行代码修复呢?kotlin中出现了可空类型以解决这个痛点。我们以如下输出字符串str的长度代码为例:
- kotlin中:
val str:String? ="hello world"
fun getLength():Int{
return str?.length?:0
}
fun main(args: Array<String>) {
println("str字符串的长度为:${getLength()}")
}
- Java代码:
public class helloword {
static String str = "hello world";
public static void main(String[] args) {
System.out.print("str 字符串的长度为:" + getLength());
}
public static int getLength() {
if (str != null) {
return str.length();
} else {
return 0;
}
}
}
在kotlin 代码中 str?.length?:0 就是 kotlin中常用的 Elvis表达式,它的意思是如果str为不空,那就返回 str.length的值,否则返回0。同样的需求,不一样量的代码,kotlin是不是显得更加精简全面呢?显然是的。
2.3 安全操作符
(1)安全调用符:"?."
val str:String? ="hello world"
fun main(args: Array<String>) {
// 方式一:
if (str != null) {
println(str.length)
}
// 方式二:
println(str?.length)
}
我们知道,在程序中,不能使用可空的对象直接调用其属性或者方法,否则会直接报错,在Java 中也会出现空指针异常。在以上代码中,在保证程序的正常执行的情况下,方式一和方式二需求一样,但是方式二使用了安全调用符 ?.是得代码更加的简洁。程序只有在str不为空的情况下才会执行 str.length的方法。
(2)Elvis运算符“?:”
在前面例子中 str?.length?:0 就使用了Elvis运算符“?:”,同理只有str不为空的情况下才会执行 str.length的方法
(3)非空断言“!!”
Kotlin中提供了断言操作符“!!”,它表示已经确定该可空对象不为空且直接调用其属性或方法。该操作符需要谨慎使用,因为一旦遇到了该对象为空的时候,则会导致空指针异常。代码及结果如下:
3.类型检测和智能类型转换
3.1 is 和 !is 运算符
is运算符是用来检测对象A是否与特定的类型X兼容(此对象A是X类型或者派生于X类型)
3.2 Java 和kotlin中的类型转换
例子:
现有一个子类,一个父类,子类和父类各自拥有一个方法
需要实现父类调用子类的方法 以及子类调用父类的方法打印输出"hello kotlin"
(1)Java 代码实现
(2)kotlin代码实现
对比以上代码可知:Java 中父类在调用子类方法获取 “kotlin”字符串的时候,编译器中进行了强制类型转换,而kotlin 代码中,父类直接调用了子类的getKotlin(),并没有进行强制类型转换,这是因为编译器已经知道它该父类本来就是子类的实例,无需再进行强转。
3.3 kotlin中智能类型转换
在kotlin中,使用 as 进行引用类型的显式类型转换类型转换,但如果类型转换失败会出现类型转换失败的异常,使用 as?运算符进行智能类型转换,当转换失败的时候直接返回null,代码如下:
fun main(args: Array<String>) {
val parent: Parent = Parent()
val child: Child? =parent as? Child
println(child?.getKotlin())
}
open class Parent{
fun getHello():String{
return "hello"
}
}
class Child : Parent() {
fun getKotlin(): String {
return "kotlin"
}
}
以上代码,父类转换为子类并调用其方法,会出现类型转换失败的异常,但是使用了as?运算符,会直接输出null而避免了异常。