为什么Kotlin能代替Java此为Android官方第一支持的开发语言?
1)Kotlin的语法更加简洁,对于同样的功能,使用Ktolin开发的代码量可能会比使用Java开发减少50%甚至更多;
2)Kotlin语法更加高级,相比于Java比较老旧的语法,Kotlin增加了很多现代高级语言的语法特性,使得开发效率大大提升;
3)Kotlin在语言安全性方面更强,几乎杜绝了空指针这个全球奔溃率最高的异常。
Kotlin有一个最为重要的特性,那就是它和Java是100%兼容的。Kotlin可以直接调用使用Java编写的代码,也可以无缝使用Java第三方的开源库。
运行Kotlin代码主要有以下三种方法:
方法一:使用IntelliJ IDEA
这是JetBrains的旗舰IDE开发工具,在IntelliJ IDEA里直接创建一个Kotlin项目,就可以独立运行Kotlin代码。
方法二:在线运行Kotlin代码
在线运行Kotlin代码网址:https://play.kotlinlang.org,只要点击右上方的“Run”即可运行Kotlin代码。
方法三:使用Android Studio
Android Studio只能创建Android项目,不能创建Kotlin项目,但是可以随便打开一个Android项目,在里面编写一个Kotlin的main()函数,就可以独立运行Kotlin代码。
如找到MainActivity所在位置,在其中编写代码。在其同级包结构下创建一个LearnKotlin文件,在其中编写main()函数,点击出现的运行小箭头即可运行。
在Java中如果想要定义一个变量,需要在变量前面声明这个变量的类型,如int a表示a是一个整型变量,String b表示b是一个字符串变量,而Kotlin中定义一个变量,只允许在变量声明两种关键字:val和var
val(value的简写)用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能被重新复制,对应Java中的final变量。
var(variable的简写)用来声明一个可变变量,这种变量在初始赋值之后仍然可以再被重新赋值,对应Java中的非final变量。
fun main(){
val a = 10
println("a = " + a)
}
注意:1)Kotlin每一行代码的结尾是不用加分号的;2)Kotlin会自动推导类型
val a: Int = 10
#对一个变量延迟赋值的话,Kotlin就无法自动推导它的类型
#如显示声明变量a为Int类型,此时Kotlin就不会再尝试进行类型推导了,如果此时将一个字符串赋值给a,那么编译器就会报错。
Java基本数据类型 | Kotlin对象数据类型 | 数据类型说明 |
---|---|---|
int | Int | 整型 |
long | Long | 长整型 |
short | Short | 短整型 |
float | Float | 单精度浮点型 |
double | Double | 双精度浮点型 |
boolean | Boolean | 布尔型 |
char | Char | 字符型 |
byte | Byte | 字节型 |
什么时候使用val?什么时候使用var?
技巧:永远优先使用val来声明一个变量,而当val没有办法满足需求时再使用var,这样设计出来的程序就会更加强壮,也更加符合高质量的编码规范。
函数是用来运行代码的载体,你可以在一个函数里编写很多行代码,当运行这个函数时,函数中的所有代码就会全部运行。
程序一旦运行,就是从main()函数开始执行的。
函数的语法规则:
fun methodName(param1: Int,param2: Int):Int{
return 0
}
fun是定义函数的关键字;
紧跟在fun后面的是函数名;
函数名后面紧跟着一对括号,里面可以声明该函数接受什么参数,参数的数量可以是任意多个,参数的声明格式是“参数名:参数类型”;
参数括号后面的那部分是可选的,用于声明该函数会返回什么类型的数据,上述示例就表示该函数会返回一个Int数据类型;
最后两个大括号之间的内容就是函数体了,可以在这里编写一个函数的具体逻辑。
fun main(){
val a = 37
val b = 40
val value = largerNumber(a,b)
println("larger number is" + value)
}
fun largerNumber(num1 : Int, num2 : Int): Int{
return max(num1 , num2)
}
程序的执行语句主要分为3种:顺序语句、条件语句和循环语句
3.1 if条件语句
Kotlin中的条件语句主要有两种实现方式:if 和 when
Kotlin中的 if 语句和Java中的 if 语句几乎没有任何区别
fun largerNumber(num1: Int,num2: Int): Int{
var value = 0
if (num1 > num2){
value = num1
} else{
value = num2
}
return value
}
注意:Kotlin中的if语句相比于Java有一个额外的功能,它是可以有返回值的!返回值就是if语句每一个条件中最后一行代码的返回值
简化后代码:
fun largerNumber(num1: Int,num2: Int): Int{
if (num1 > num2){
num1
} else{
num2
}
}
语法糖:当一个函数只有一行代码时,可以省略函数体部分,直接将这一行代码使用等号串连在函数定义的尾部
使用语法糖简化:
fun largerNumber(num1: Int,num2: Int) = if (num1 > num2){
num1
}else{
num2
}
3.2 when语句
Kotlin中的when语句有点类似于Java中的switch语句,但它又远比switch语句强大的多。
fun getScore(name: String) = if (name == "Tom"){
86
}else if (name == "Jim"){
77
}else if(name == "Jack"){
95
}else if(name == "Lily"){
100
}else{
0
}
将代码改成when语法
fun getScore(name: String) = when(name){
"Tom" -> 86
"Jim" -> 77
"Jack"-> 95
"Lily"->100
else ->0
}
when语句允许传入一个任意类型的参数,然后可以在when的结构体中定义一系列的条件,语法格式:
匹配值 -> { 执行逻辑 }
当执行逻辑只有一行代码时,{ }可以省略
3.3 循环语句
Java中主要有两种循环语句:while循环和for循环,而Kotlin也提供了这两种,其中while和Java基本一致。
Kotlin在for循环方面做了很大幅度的修改,Java中最常用的for-i循环在Kotlin中直接被舍弃,而Java中另一种for-each循环在Kotlin变成了for-in循环
Kotlin代码表示一个区间:
val range = 0..10
上述代码表示创建了一个0到10的区间,并且两端都是闭区间
使用for-in循环来遍历这个区间
fun main(){
for(i in 0..10){
println(i)
}
}
Kotlin中可以使用until关键字来创建一个左开右闭的区间:
val range = 0 until 10
上述代码表示创建了一个0到10的左开右闭区间,它的数学表达式为【0,10)
fun main(){
for(i in 0 until 10 step 2)
}
for-in循环每次执行循环时会在区间范围内递增1,如果想要跳过一些元素,可以使用step关键字
上述代码表示在遍历【0,10)这个区间的时候,每次执行循环都会在区间范围内递增2
如果想要创建一个降序的区间,可以使用downTo关键字
fun main(){
for(i in 10 downTo 1){
println(i)
}
}
类就是对事物的一种封装,而类又可以拥有自己的字段和函数,字段表示该类所拥有的属性,比如说人可以拥有姓名和年龄;而函数则是表示该类可以有哪些行为,比如人可以吃饭和睡觉等
Kotlin也是使用class关键字来声明一个类的
class Person{
var name = ""
var age = 0
fun eat(){
println(name + "is eating.He is " + age + "years old.")
}
}
实例化对象
val p = Person()
Kotlin中实例化一个类的方式和Java是基本类似的,只是去掉了new关键字
在main()函数中对p对象进行一些操作
fun main(){
val p = Person()
p.name = "Jack"
p.age = 19
p.eat()
}
这就是面向对象编程最基本的用法,就是要先将事物封装成具体的类,然后将事物所拥有的属性和能力分别定义成类中的字段和函数,接下来对类进行实例化,再根据具体的编程需求调用类中的字段和方法即可。
想要让Student类继承Person类,需要做两件事:
1、第一件事,使Person类可以被继承
在Kotlin中任何一个非抽象类默认都是不可以被继承的。
在Person类的前面加上open关键字就可以:
open class Person{
...
}
加上open关键字之后,我们就是在主动告诉Kotlin编译器,Person这个类是专门为继承而设计的,这样Person类就允许被继承了
2、第二件事,要让Student类继承Person类,在Java中继承的关键字是extends,而在Kotlin中变成了一个冒号:
class Student : Person(){
var sno = ""
var grade = 0
}
在Kotlin中,将构造函数分为了两种:主构造函数和次构造函数
1、主构造函数
主构造函数将会是最常用的构造函数,每个类默认都会有一个不带参数的主构造函数,当然也可以显示地给它指明参数。主构造函数的特点就是没有函数体,直接定义在类名的后面即可。
class Student(val sno : String, val grade : Int) : Person(){
}
我们将学号和年级这两个字段都放到了主构造函数当中,这就表明在对Student类进行实例化的时候,必须传入构造函数中要求的所有参数,如:
val student = Student("a123",5)
你可能会问,主构造函数没有函数体,如果我想在主构造函数中编写一些逻辑,该怎么办?
Kotlin给我们提供了一个init结构体,所有主构造函数中的逻辑都可以写在里面:
class Student(val sno:String, val grade:Init) : Person(){
init{
println("sno is" + sno)
println("grade is" + grade)
}
}
2、次构造函数
几乎是用不到次构造函数的,次构造函数是通过constructor关键字来定义的
class Student(val sno : String, val grade : Init, name : String, age: Int): Person(name,age){
constructor(name: String, age : Int) : this("",0,name,age){
}
constructor():this("",0){
}
}
这里我们定义了两个次构造函数,第一个次构造函数接受name和gae参数,然后它又通过this关键字调用了主构造函数,并将sno和grade这两个参数赋值成初始值;第二个次构造函数不接受任何参数,它通过this关键字调用了我们刚才定义的第一个次构造函数,并将name和age参数也赋值成初值,由于第二个次构造函数间接调用了主构造函数,因此这仍然是合法的。
Kotlin中的接口部分和Java几乎是完全一致的,接口是实现多态编程的重要组成部分,Kotlin是单继承结构的语言,任何一个类最多只能继承一个父类,但是却可以实现任意多个接口。
interface Study{
fun readBooks()
fun doHomework()
}
class Student(name : String, age : Int): Person(name, age), Stduy{
override fun readBooks(){
println(name + "is reading.")
}
override fun doHomework(){
println(name + "is doing homework.")
}
}
上述代码就表示Student类继承了Person类,同时还实现了Study接口。
Java中继承使用的关键字是extends,实现接口使用的是关键字implements,而Kotlin中统一使用冒号,中间用逗号进行分隔,另外接口的后面不用加上括号,因此它没有构造函数可以去调用。
Kotlin中使用override关键字来重写父类或者实现接口中的函数。
在main()函数中编写如下代码来调用这两个接口中的函数:
fun main(){
val student = Student("Jack",19)
doStudy(student)
}
fun doStudy(study: Study){
study.readBookes()
study.doHomeword()
}
Kotlin还增加了一个额外的功能:允许对接口中定义的函数进行默认实现。
interface Study{
fun readBooks()
fun doHomework(){
println("do homework default implementation.")
}
}
如果接口中的一个函数拥有了函数体,这个函数体中的内容就是它的默认实现。
现在当一个类去实现Study接口时,只会强制要求实现readBooks()函数,而doHomework()函数则可以自由选择实现或者不实现,不实现时就会自动使用默认的实现逻辑。
函数的可见修饰符:
修饰符 | Java | Kotlin |
---|---|---|
public | 所有类可见 | 所有类可见(默认) |
private | 当前类可见 | 当前类可见 |
protected | 当前类、子类、同一包路径下的类可见 | 当前类、子类可见 |
default | 同一包路径下的类可见(默认) | 无 |
internal | 无 | 同一模块下的类可见 |