Kotlin 的变量、函数和类型
2019-12-16 本文已影响0人
吐必南波丸
变量
变量声明:var 、val 、lateinit
- 类型和变量名位置互换了
- 中间是用冒号分隔的
- 结尾没有分号(对,Kotlin 里面不需要分号)
var name: String? =null
这种类型之后加 ? 的写法,在 Kotlin 里叫可空类型
- val 只读变量
- 只能复制一次,不能修改 类似java中的final
- lateinit 延迟初始化
- 意思是:告诉编译器我没法第一时间就初始化,但我肯定会在使用它之前完成初始化的。
lateinit var textView: TextView
var name:String =null
类似java中的final
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_first)
textView = findViewById(R.id.tv_textView)
}
类型推断
Kotlin 有个很方便的地方是,如果你在声明的时候就赋值,那不写变量类型也行:
🏝️
var name: String = "Mike"
👇
var name = "Mike"
函数
Kotlin 除了变量声明外,函数的声明方式也和 Java 的方法不一样。Java 的方法(method)在 Kotlin 里叫函数(function),其实没啥区别,或者说其中的区别我们可以忽略掉。对任何编程语言来讲,变量就是用来存储数据,而函数就是用来处理数据。
函数的声明
java
Food cook(String name) {
...
}
🏝️kotlin
👇 👇
fun cook(name: String): Food {
...
}
- 以 fun 关键字开头
- 返回值写在了函数和参数后面
基本类型
- 在 Kotlin 中,所有东西都是对象,Kotlin 中使用的基本类型有:数字、字符、布尔值、数组与字符串。
🏝️
var number: Int = 1 // 👈还有 Double Float Long Short Byte 都类似
var c: Char = 'c'
var b: Boolean = true
var array: IntArray = intArrayOf(1, 2) // 👈类似的还有 FloatArray DoubleArray CharArray 等,intArrayOf 是 Kotlin 的 built-in 函数
var str: String = "string"
类和对象
- 首先是类的可见性,Java 中的 public 在 Kotlin 中可以省略,Kotlin 的类默认是 public 的。
- 类的继承的写法,Java 里用的是 extends,而在 Kotlin 里使用 :,但其实 : 不仅可以表示继承,还可以表示 Java 中的 implement。
- 举个例子,假设我们有一个 interface 叫 Impl:
🏝️
interface Impl {}
☕️java
public class Main2Activity extends AppCompatActivity implements Impl { }
🏝️kotlin
class MainActivity : AppCompatActivity(), Impl {}
- 构造方法的写法不同。
☕️ java
public class MainActivity extends AppCompatActivity {
// 👇默认构造函数
public MainActivity() {
}
}
🏝️ kotlin
class MainActivity constructor() : AppCompatActivity() {
👆
}
- override 的不同
- Java 里面 @Override 是注解的形式。
- Kotlin 里的 override 变成了关键字。
- Kotlin 省略了 protected 关键字,也就是说,Kotlin 里的 override 函数的可见性是继承自父类的。
除了以上这些明显的不同之外,还有一些不同点从上面的代码里看不出来,但当你写一个类去继承 MainActivity 时就会发现:
- Kotlin 里的 MainActivity 无法继承:
🏝️
// 👇写法会报错,This type is final, so it cannot be inherited from
class NewActivity: MainActivity() {
}
- 原因是 Kotlin 里的类默认是 final 的,而 Java 里只有加了 final 关键字的类才是 final 的。
那么有什么办法解除 final 限制么?我们可以使用 open 来做这件事:
🏝️
open class MainActivity : AppCompatActivity() {}
这样一来,我们就可以继承了。
🏝️
class NewActivity: MainActivity() {}
类型的判断和强转
- 刚才讲的实例化的例子中,我们实际上是把子类对象赋值给父类的变量,这个概念在 Java 里叫多态,Kotlin 也有这个特性,但在实际工作中我们很可能会遇到需要使用子类才有的函数。
比如我们先在子类中定义一个函数:
🏝️
class NewActivity : MainActivity() {
fun action() {}
}
那么接下来这么写是无法调用该函数的:
🏝️
fun main() {
var activity: Activity = NewActivity()
// 👆activity 是无法调用 NewActivity 的 action 方法的
}
在 Java 里,需要先使用 instanceof 关键字判断类型,再通过强转来调用:
void main() {
Activity activity = new NewActivity();
if (activity instanceof NewActivity) {
((NewActivity) activity).action();
}
}
Kotlin 里同样有类似解决方案,使用 is 关键字进行「类型判断」,并且因为编译器能够进行类型推断,可以帮助我们省略强转的写法:
🏝️
fun main() {
var activity: Activity = NewActivity()
if (activity is NewActivity) {
// 👇的强转由于类型推断被省略了
activity.action()
}
}
那么能不能不进行类型判断,直接进行强转调用呢?可以使用 as 关键字:
🏝️
fun main() {
var activity: Activity = NewActivity()
(activity as NewActivity).action()
}
这种写法如果强转类型操作是正确的当然没问题,但如果强转成一个错误的类型,程序就会抛出一个异常。
我们更希望能进行安全的强转,可以更优雅地处理强转出错的情况。
这一点,Kotlin 在设计上自然也考虑到了,我们可以使用 as? 来解决:
🏝️
fun main() {
var activity: Activity = NewActivity()
// 👇'(activity as? NewActivity)' 之后是一个可空类型的对象,所以,需要使用 '?.' 来调用
(activity as? NewActivity)?.action()
}
它的意思就是说如果强转成功就执行之后的调用,如果强转不成功就不执行。