严格的数据类型验证
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 等)。