Kotlin 数据之本变量
变量和常量用来存储数据和传递数据,类型则用来描述变量和常量保存的是什么样的数据类型。
数据类型
变量和常量都有数据类型,数据类型用来描述变量和常量保存的数据,告诉编译器该如何进行类型检查。理论结合实践,我们创建一个新项目,项目名,VarType(变量类型)。
使用IntelliJ创建新项目
第一次打开IntelliJ集成开发环境,点击New Project
选择Kotlin,选择 JVM | IDEA,表示用Java JVM 开发Kotlin编程。
点击Next,如图
最后点击Finish,项目创建完成。
右键src,选择New,选择Kotlin File/Class
选择File,输入TypeIntro,按下回车后新文件会在编辑器中打开。
输入main函数
fun main() {
}
变量声明
在TypeIntro中创建一个apple变量,表示有6个苹果
fun main() {
var apple: Int = 6 // 有6 个苹果
println(apple) // 打印苹果变量值到控制台
}
上述代码中,将一个Int类型值赋给了apple。var关键字定义了一个变量。var 后面跟着变量名,便是你想定义一个新变量。使用:Int
指定变量的类型,:Int
变量表明apple要存储的是整数。使用赋值运算符(=) 把右边的实例值6
赋值给左边的apple。 // 代表注释,会完全忽略注释
变量定义的图解
定义变量并赋值,接下来使用println函数将变量值输出到控制台。
现在,尝试将apple 变量赋值 "red"
我们看到有一个红色的波浪线,编译器说字符串实例不能赋值给Int类型。我们把鼠标放到红色的波浪线上,会有一个错误提示弹框。我们输入的每一个字符,每一行代码,都在和编译器沟通,编译器一直在做语法检查。确保每行代码都符合语法要求!就像我们学习英语的时候,语法决定了语句的正确性!
为了改正错误类型,我们将apple实例值改为5。
fun main() {
var apple: Int = 5
println(apple)
}
班里现在有10哥同学,5个苹果不够吃,我们在增加5个苹果。
fun main() {
var apple: Int = 5
apple += 5
println(apple)
}
现在我们总共有了10个苹果,运行代码,看看结果
我们先来看看最常用的类型
类型 | 描述 | 示例 |
---|---|---|
String | 字符串 | "Apple" |
char | 单字符 | 'X' |
Int | 整数 | 6 |
Boolean | true/false值 | true |
Double | 小数 | 3.14 |
List | 元素集合 | 1,2,4 |
Set | 无重复元素结合 | "Hello" "WOrld" |
Map | 键值对 | "apple" to 6,"banana" to "8" |
只读变量
前面你已经看到,变量可以重新赋值。但通常我们也需要不能在重新赋值的变量。例如,丈夫的工资都在媳妇的银行卡里,媳妇给了丈夫每天60元生活费,除此之外丈夫身无分文,媳妇不希望丈夫有更多的钱,我们来定义一个丈夫的生活费变量。
fun main() {
var apple: Int = 5
apple += 5
println(apple)
val husbandExpense = 60 // 媳妇定义了丈夫每天60元的生活费,媳妇不希望丈夫有更多的钱
husbandExpense +=100 // 丈夫想要更多的钱,那是不可能地,你会发现这行代码出错了
println(husbandExpense)
}
只读变量只能在定义时赋初值,以后不能在改它的值。我们注释掉丈夫生活费增加100元的那行代码,如下所示:
现在运行代码,看看输出结果
10
60
Process finished with exit code 0
编译器在我们输入代码时,能判定可变变量和只读变量是否运用恰当。如果一个不可变变量使用了var 关键字,编译器会提示我们改为val。我们只要有必要,都建议使用 val 关键字。
类型推断
注意看上面的代码,只读变量 husbandExpense 我们没有加变量类型,编译器使用了类型推断。对于以声明并赋值的变量,编译器清楚的知道这个变量的类型是什么。它允许你省略类型定义!
我们再注意看一开始定义的 apple 可变变量,:Int
是灰色的,编译器说类型定义是多余的,对于以声明并赋值的变量,已经精确的给出了类型,这就是Kotlin的自动类型推断。
单击 apple 变量旁边的Int 类型定义,然后按下(Alt + Enter)组合键,如图
按下回车键,IntelliJ 能够自动帮你删除冗余的代码。可以看到 Int 类型定义不见了。我们以后编写代码都不会明确指定变量的类型,除非有歧义,这样的代码编写的更简洁!
我们按下 Ctrl + Shift + P 组合键,IntelliJ 会自动显示出变量的类型。
编译时常量
编译时常量只能在函数之外定义,只是因为编译时常量,只能在编译时赋值,而main函数和其它函数都是在运行时才调用。函数内的变量也是在那是赋值的。
因为使用复杂的数据类型可能会危害编译时的安全保障,所以编译时常量只能是一些常见的基本数据类型。基本数据类型我们很快就会全部学完。
使用const 修饰符定义一个编译时常量
//媳妇很坚定的说,你每天最多只有60元生活费,而且这辈子我说了算
const val MAX_EXPENSE: Int = 60
fun main() {
}
MAX_EXPENSE 由 const 和 val 修饰符一起告诉编译器,MAX_EXPENSE 常量值绝不会改变。这也就是说,整数值60要绝对保证不变。编译器就知道如何灵活处理代码。
对 MAX_EXPENSE 的书写格式感到好奇吗?没错,为了凸显编译时常量,我们都是这么写的。
前面不是有只读变量吗,为什么要加编译时常量呢!因为只读变量不能保证变量一定不能修改。
常量Kotlin 字节码,看下图
熟悉Java 的朋友阅读起来很熟悉,不熟悉Java的朋友做个参数
import kotlin.Metadata;
@Metadata(
mv = {1, 1, 16},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u000e\n\u0000\n\u0002\u0010\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0002\u001a\u00020\u0003\"\u000e\u0010\u0000\u001a\u00020\u0001X\u0086T¢\u0006\u0002\n\u0000¨\u0006\u0004"},
d2 = {"MAX_EXPENSE", "", "main", "", "VarType"}
)
public final class TypeIntroKt {
public static final int MAX_EXPENSE = 60;
public static final void main() {
int apple = 5;
int apple = apple + 5;
boolean var1 = false;
System.out.println(apple);
int husbandExpense = 60;
boolean var2 = false;
System.out.println(husbandExpense);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
我们发现Kotlin源码中定义的 Int 引用数据类型,翻译成Java源码后是基本数据类型。Kotlin 没有基本数据类型,Kotlin 编译器会根据情况,将引用数据类型编译成基本数据类型,以提高代码的性能。Kotlin在背后为我们做了许多事情,背后的故事我们来看两个变量。注意观察 apple 变量 和 husbandExpense 变量的定义:
var apple = 5
val husbandExpense = 60
在Kotlin 源码中,我们已经省略了变量类型的定义,但在字节码中,我们反编译字节码,得到Java代码,还是看到它们的显示类型定义。由此可见,字节码讲述了背后的故事,即Kotlin支持类型推断,所以不像Java那样,需要显示指定变量类型定义。
我们在这里学习了可变变量和只读变量存储基本数据,知道何时改用哪种变量。这主要取决于变量值是否能修改;了解了如何使用编译时常量定义不可变变量;学会了使用Kotlin自动类型推断,在声明时简化代码书写。后面我们会反复用到这些知识。下一章我们将学习条件语句,写一个简单的计算器。