轻松掌握Kotlin的基本要素
作者:互联网
在上一篇文章中,我们初步了解了什么是Kotlin,重点关注其与Java的互操作性,了解了Kotlin的主要特征以及在Android Studio中如何将Java代码转换为Kotlin代码。如果您还没有阅读,可以先阅读后再进行下一步学习。本文主要介绍Kotlin的基本要素:变量、函数和类以及属性首先我们先来学习函数和变量。
1、基本要素:函数和变量
现在,我们就从最最最经典的例子开始:打印一个“Hello world!”。代码如下:
@Test
fun main(args:Array<String>){
println("Hello world!")
}
从上面的代码中,我们可以观察到:
- 使用关键字fun来声明一个函数。
- 参数的类型写在它的名称后面,变量的声明也一样。
- 函数可以定义在文件的最外层,不需要把它放在类中。
- 数组就是类。和Java不同,Kotlin没有声明数组类型的特殊语法。
- 使用print()/println()来进行输出。
- 可以省略每行代码结尾的分号。
是不是看起来很爽,那么接下来让我们看下函数声明的语法。
1.1 函数
//Kotlin函数声明:
//fun 函数名(参数列表):返回类型{函数体}
fun max(a:Int,b:Int):Int{
return if (a > b) a else b
}
在上面的例子中,我们使用关键字fun声明了一个max函数用来比较两个数值的大小,并返回数值大的那一个,可以看出返回值是跟在参数列表后的,并用一个冒号隔开。注意在Kotlin中,if是有结果值的表达式,它和Java中的三元运算符相似:(a>b)?a:b。
表达式函数体(很重要)
我们可以来优化上面的代码。因为它的函数体是由单个表达式构成的,可以用这个表达式作为完整的函数体,并去掉花括号和return语句:
fun max(a:Int,b:Int):Int
= if (a > b) a else b
如果函数体写在花括号中,这个函数有代码块体。如果它直接返回一个表达式,则其有表达式体。
甚至,我们还可以将返回类型给省掉,如下:
fun max(a:Int,b:Int)
= if (a > b) a else b
对表达式体函数来说,编译器会分析作为函数体的表达式,并把它的类型作为函数的返回类型,即使没有显式地写出来,这就是类型推导。
注意:只有表达式体函数的返回类型可以省略。对于有返回值的代码块体函数,必须显式地写出返回类型和return语句。
1.2 变量
在Kotlin中,变量以关键字开始,然后是变量名称,最后可以加上类型(可不加),例如:
val str:String = "Hello world!"
var a = 1 //类型可以被推导出来
如果变量没有初始化器,需要显式地指定它的类型:
val b:String
b = str
如果不能提供可以赋给变量的值的信息,编译器就无法推断出它的类型。
可变变量和不可变量
- val:不可变引用。使用val声明的变量不能在初始化之后再次赋值,它对应的是Java的final变量。
- var:可变引用。这种变量的值可以被改变,对应的是普通(非final)的Java变量。
默认情况下,应该尽可能地使用val关键字来声明所有的Kotlin变量,仅在必要的时候换成var。使用不可变引用、不可变对象及无副作用的函数让代码更接近函数式编程风格。
在定义了val变量的代码块执行期间,val变量只能进行唯一一次初始化。但是,如果编译器能确保只有唯一一条初始化语句会被执行,可以根据条件使用不同的值来初始化它,如下代码:
val message:String
if (condition){
message = "true"
}else {
message = "false"
}
注意,尽管val引用自身是不可变的,但是它指向的对象可能是可变的,如下代码:
//声明不可变引用
val languages = arrayListOf("Java")
//改变引用指向的对象
languages.add("Kotlin")
var关键字允许变量改变自己的值,但它的类型却是改变不了的,如下代码:
var a = 1
a = "heidou"//报错,类型不匹配
//可以使用"xx".toInt()来进行强转
1.3 字符串模板
Kotlin允许在字符串字面值中引用局部变量,只需要在变量名称前面加上字符$,如下代码:
val str = "heidou"
println("我的名字叫$str")
//使用复杂表达式需要使用花括号{}括起来
println(println("1 + 3 = ${1+3}"))
2、类和属性
在Kotlin中,我们可以用更少的代码来完成许多常见的任务,例如定义一个学生类JavaBean,代码如下:
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Student类中只有一个name属性。在Java中,构造方法的方法体常常包含完全重复的代码:它把参数赋值给有着相同名称的字段。在Kotlin中,这种逻辑不用这么多的样板代码就可以表达。在Android Studio中点击“Code"–>"Convert Java File to Kotlin File”将上面的Java类转换为Kotlin类,代码如下:
//这种类(只有数据没有其它代码)通常被叫作值对象
class Student(var name: String)
是不是感觉很简洁,我们再也不用编写过多的重复代码了,美滋滋。
注意:从Java到Kotlin的转换过程中public修饰符不见了。在Kotlin中,public是默认的可见性,所以可以省略。在后续文章中我们会对Kotlin的可见性进行详细讲解。
2.1 属性
类的概念就是把数据和处理数据的代码封装成一个单一的实体。在Java中,数据存储在字段中,通常还是私有的。我们会提供访问器方法getter和setter用来让类的使用者访问到数据。例如上面Student类,在getter和setter中我们还可以添加额外的逻辑。
在Java中,字段和其访问器的组合常常被叫作属性。在Kotlin中,属性是头等的语言特性,完全代替了字段和访问器方法。在类中声明一个属性和声明一个变量一样:使用val和var关键字。声明成val的属性是只读的,而var属性是可变的。
class Student(
//可写属性:生成一个字段、一个getter和一个setter
var name: String,
//只读属性:生成一个字段和一个getter
val score:Int
)
当我们声明属性的时候,就已经声明了对应的访问器(getter、setter)。访问器的默认实现非常简单:创建一个存储值的字段,以及返回值的getter和更新值的setter。有必要的时候,我们也可以自定义我们想要的访问器,自定义访问器在下面会进行介绍。
如何在Java中使用Kotlin定义的类。Kotlin Student类声明隐藏了和原始Java代码相同的底层实现:它是一个字段都是私有的类,这些字段在构造方法中初始化并能够通过对应的getter、setter访问。代码如下:
@Test
public void main() {
Student stu = new Student("Heidou", 100);
System.out.println("name = " + stu.getName()
+ " , score = " + stu.getScore());
}
//输出:name = Heidou , score = 100
注意:如果属性名称是以is开头,getter不会增加任何的前缀,而setter名称中is会被替换成set。
在Kotlin中使用,代码如下:
val stu = Student("Heidou",100)
stu.name = "Hei_dou"
println("name = ${stu.name} , score = ${stu.score}")
//输出:name = Hei_dou , score = 100
可以看到,使用kotlin可以直接引用属性,不再需要调用setter和getter,是不是很方便呢?接下来我们来看看怎么进行自定义访问器。
额外知识点:对于那些在Java中定义的类,一样可以使用Kotlin的属性语法。Java类中的getter可以被当成val属性在Kotlin中访问,而一对getter/setter可以被当成var属性访问。
2.2 自定义访问器
我们来声明一个矩形,它能够判断自己是否是正方形。不需要一个单独的字段来存储这个信息(是否是正方形),因为可以随时通过检查矩形的长度是否相等来判断,代码如下:
class Rectangle(val height: Int, val width: Int) {
val isSquare: Boolean
//声明属性的getter
get() = height == width
}
val rectangle = Rectangle(200,200)
println(rectangle.isSquare) //输出true
属性isSquare不需要字段来保存它的值。它只有一个自定义实现的getter,它的值是每次访问属性的时候计算出来的。
再看看下面的例子,我们可以同时编写getter和setter访问器,代码如下:
class Person{
var age:Int = 0
set(value){
field = value + 1
}
get() = field - 1
}
//field关键字代表的是当前域
2.3 Kotlin源码布局:目录和包
每一个Kotlin文件都以一条package语句开头,而文件中定义的所有声明(类、函数及属性)都会被放到这个包中。如果其它文件中定义的声明也有相同的包,这个文件可以直接使用它们:如果包不相同,则需要用import关键字导入它们。例如:
package com.heidou.xxx
import org.junit.Test
Kotlin不区分导入的是类还是函数,而且,它允许使用import关键字导入任何种类的声明。可以直接导入顶层函数的名称。可以在包名称后加上.*来导入特定包中定义的所有声明。注意这种星号导入不仅让包中定义的类可见,也会让顶层函数和属性可见。
注意:在Kotlin中,可以把多个类放在同一个文件中,文件的名称还可以随意选择。Kotlin也没有对磁盘上源文件的布局强加任何限制。如下所示,包层级结构不需要遵循目录层级结构。
会生成包second.SecondTest以及second.Student。
使用技巧:建议把多个类放在同一个文件中,特别是那些很小的类。
最后,我们来拓展一下,看看语句和表达式的区别:
语句和表达式的区别在于,表达式有值,并且能作为另一个表达式的一部分使用;而语句总是包围着它的代码块中的顶层元素,并且没有自己的值。在Java中,所有控制结构都是语句,而在Kotlin中,除了循环(for、while和do-while)以外大多数控制结构都是表达式。
另一方面,Java中的赋值操作是表达式,在Kotlin中则变成了语句,这有助于避免比较和赋值之间的混淆。
借鉴资料:《Kotlin实战》
有兴趣的读者可以关注我的微信公众号,萌新一个,希望大家多多支持。我会在接下来的每个星期二、四、六把自己学习内容笔记同步到微信公众号。
标签:Java,函数,val,Kotlin,代码,轻松,基本要素,name 来源: https://blog.csdn.net/weixin_41953808/article/details/111569136