Kotlin 与 Java 间的数据类型类型对比

2019年9月6日05:46:37 发表评论 48 views

严格的数据类型验证

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

在 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 等)。

作者:奇舞移动
链接:https://juejin.im/post/5d70ca45e51d453c12504e65
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: