Kotlin第二讲——数据类型与Java的对比

avatar
Android @奇舞团Android团队
原文链接: mp.weixin.qq.com

内容简介:通过前文的数据类型介绍,我们今天来看一下 Kotlin 与 Java 间的数据类型类型对比。

严格的数据类型验证

java 的世界中,基本数据数据类型不同也是可以赋值操作的( java 处于睁一只眼闭一只眼的情况)例如:

    public static void main(String[] args) {

    int a = 10;

    /**

    * 这种情况,java 是支持的,因为不存在精度丢失的情况

    */

    long b = a;

    }

Kotlin 具有严格的数据类型判断,不同的类型是不允许赋值操作的。如:

    fun main() {

    val a:Int = 10

    /**

    * 将 Int 类型的 a 赋值给 Long 类型的 b ,必须要将变量 a 转换成 Long 类型

    */

    val b:Long = a.toLong()

    }

==  和 equals

符合 == 的含义变成了equals

在 java 的世界中 == 的本质都是在对比 2 个数字的值是否相同(引用类型对比地址,地址也是一个 int 类型的数字)。我前面说过 kotlin 已经不存在基本数据类型,所以 == 的含义也发生了变化,全部变成了调用 equals 方法。如:

                        

    class MyInt {

    var value = 0

    /**

    * 只要重写equals方法,就可以实现对象的==比较

    */

    override fun equals(other: Any?): Boolean {

    if (other is MyInt ){

    return other.value == this .value

    }

    return false

    }

    }

这里是不是可以联想到Kotlin的 String 字符串,为何直接可以使用 ==做字符串相同比较呢?

null 与非 null 类型

kotlin 中定义的变量类型,不光需要指定数据类型,还需要指定是否可为 null 的类型。定义可 null 和不可 null 类型:

    fun main() {

    /**

    * 定义可空字符串,只需要在数据类型后面加 ?

    */

    val str: String? = null

    /**

    * 普通定义的变量是不可 null 类型,需要赋值.并在后面调用的过程中,必须确保不可为 null

    */

    val noNStr: String = "我是不可空字符串"

    }

这里补充一点,kotlin 调用java方法返回的对象,会是新的类型 ?! 。这种类的在kotlin中属于不可为 null 的类型。但是 java 返回的是一个 null 的话,kotlin直接调用,就会报 空指针异常。

聪明的空类型判断

在java的编程世界中,最常见的就是 NullPointerException 。kottlin 的设计师为我们想到了这个头疼的问题,在编码的过程中尽量规避这个异常(当然不代表100%规避)。例如:

                            

    fun main() {

    /**

    * 定义可空字符串

    */

    val str: String? = null

    val noNStr: String = "我是不可空字符串"

    /**

    * 在后续的使用过程中,可 null 的对象,都会有一个判断

    * 字段名加?代表,如果 str 为 null 就返回 null

    */

    val length = str?.length

    /**

    * 字段名加 !! 代表强制 str 不可能为 null ,这样如果也会执行去长度方法。如果 str 为 null 就会抛异常

    */

    val length2 = str!!.length

    }

运用方式 解释
val str: String? = null 定义变量的时候,代表可null类型
str?.length 属性方法调用时候,如果对象为null,不调用方法,直接返回null
?: 若前面的表达式,结果为null直接调用,后面的表达式

当时 ?: 和 str?.length 理解的不是很清晰,本质上这2个语法是不同的功能。我就是犯了这个错误。。例如:

    fun main() {

    val str:String?=null

    /**

    * 我们经常写的语句,对象为null返回逻辑,可以缩写成:

    */

    str?:return

    }

经常写适配器,长度的方法:

    /**

    * 我们经常写的adapter长度方法

    */

    fun getSize(): Int {

    return datas?.size ?: 0

    }

智能类型转换

在java 中判断一个对象类型,使用关键词 instanceof 。 在Kotlin 中使用 is 关键词,你以为就是缩短了关键词这么简单吗? kotlin 隐藏着一个类型转换的过程。 例如写了个 if 语句,逻辑判断我是不是程序员?如果是,if 内的逻辑会自动将我转换成程序员,并持有程序员的特性。例如:

下方内容存在部分,kotlin 类的知识,后续会讲。

    /**

    * 定义 程序员 子类

    */

    class CodePople(name: String, age: Int) : People(name, age) {

    /**

    * 定义敲代码方法

    */

    fun codeing() {

    println("敲代码")

    }

    }

    fun main() {

    /**

    * 定义我的数据类型,我是一个程序员(注意我这里定义的类型是 People )

    */

    val my: People = CodePople("阿文", 18)

    /**

    * 类型判断

    */

    if (my is CodePople) {

    /**

    * 重点: 可以看到我已经可以直接调用程序员的方法了. my 类型已经自动转换成了 CodePople

    */

    my.codeing()

    }

    }

你以为这样就结束了?就这么点小智能?当然不是,还记得 kotlin 中存在 null 类型和不可为 null 吗?可null 类型的变量,是不可以赋值给不可为 null 的变量的哦(印证了 kotlin 中类型的赋值的严格校验)。

kotlin 中可 null & 不可 null 的智能转换:

    fun main() {

    /**

    * 定义可 null 变量

    */

    var nullString: String? = null

    /**

    * 定义不可 null 变量

    */

    var str = "1231"

    /**

    * 如果可 null 变量,为空返回

    */

    nullString ?: return

    /**

    * 你会发现可 null 变量,已经智能转换成,不可为 null 的变量了

    */

    str = nullString

    }

val 与 var 的区别

kotlin 中定义变量需要使用 val 与 var 关键词

  • val修饰,定义不可变变量。类似java中final修饰(并不是完全相同)

  • var修饰,定义可变变量。

val 定义变量是不可以修改的,并且要在定义的时候初始化或者委托给另外方法(委托的概念后续会讲)。kotlin 中 val 的定义变量都有1个隐藏的方法 get 方法,当获取本变量的值的时候,就会调用。 var 定义的可变变量,都有2个隐藏的方法 get & set方法,当获取本变量的值调用 get,设置变量的值时调用 set 。

例如:

    class CoreDemo {

    /**

    * 例如这个方法,可以修改值,如果内容为空,就展示另外一个内容

    */

    val str: String = ""

    get() {

    // 对于field就(幕后字段),他就是修改当前变量字段值

    return if (field.isEmpty()) {

    "我不能为null"

    } else {

    field

    }

    }

    var str2: String = ""

    /**

    * 当获取值的时候调用

    */

    get() {

    if (field == "new")

    return "old"

    else {

    field

    }

    }

    /**

    * 当设置新值的时候调用

    */

    set(value) {

    /**

    * 如果设置的值时候new,不允许修改

    */

    if (value != "new") {

    field = value

    }

    }

    }

kotlin 中的 val 和 java 中的 final 修饰的变量是存在不同的哦。java 中 final 修饰的变量,在编译期就知道了该变量的值是多少。所以在引用的此变量时候就会直接使用此值(编译器替换)。kotlin的 val 变量是不会替换的。如果想要替换使用 const 修饰

is 关键字

java中我们经常使用 instanceof 判断类型。kotlin中不存在词关键词了,与之替换的是 is 关键词

    fun main() {

    val d = 0

    if (d is Number){

    println("这家伙是个数")

    }

    }

as 和安全的类型转换

java中有强制类型转换(直接前面加 ())。kotlin中的强转变成了使用关键词 as 。

    fun main() {

    val d = 0

    /**

    * 使用关键词as,当然这样转换肯定会抛出异常(int到double使用toDouble()方法)

    * class java.lang.Integer cannot be cast to class java.lang.Double

    */

    val double = d as Double

    }

kotlin中独有安全类型转换

    fun main() {

    val d = 0

    /**

    * 使用关键词as?,理论上会抛出以下异常

    * class java.lang.Integer cannot be cast to class java.lang.Double

    * 但是使用的as?,如果转换异常,会返回null(再配合?:语法,简直是天衣无缝),不会抛出异常

    */

    val defaultValue = 0.0

    val double = d as? Double ?: defaultValue

    println(double)

    }

延迟加载

前面说过,kotlin 的变量类型,新增了可 null 和不可 null。但是有时候特殊情况,我们知道这个变量是不可为 null 的,但是初始化这个变量,还需要其他运行时候产生的条件,可以通过 lateinit 关键词。

    class CoreDemo {

    /**

    * 延迟初始化 lateinit var

    * 个人意见,能规避吊这种写法,就规避掉.打破了kotlin的非空安全机制

    */

    lateinit var value: String

    fun test() {

    value = ""

    }

    }

总结

在学习 kotlin 数据类型篇章过程中,发现相比较java来说,kotlin 去其糟粕取其精华。在数据类型这块,kotlin 对比 java 做的更加的好。相比来说 java 的强类型语言,kotlin 给我的感觉越来越像javaScript语言靠近。 智能类型推倒,智能类型转换,都是相当不错的设计方案。koltin 在经常出现的 null 指针设计理念还是很惊艳的,将这种异常大部分暴露在编译期。kotlin 没有 java 的基本数据类型的概念了。 kotlin 都将 java 的基本类型,进行了包装(类似 java 的 Integer 等)。

--END--

识别二维码,关注我们