Kotlin快速入门:基础语法类与继承集合

Posted 舒泱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin快速入门:基础语法类与继承集合相关的知识,希望对你有一定的参考价值。

参考书籍:

  • 《AtomicKotlin》,全英文,读起来慢,但是写得很详细,没有任何语言基础的也能看懂
  • 《第一行代码 android 第三版》,第二章,有java基础的看一看就会了
  • Kotlin中文文档,很详细,可以当作字典查看,挨着看有点太多了

       

       

       

       

1 基础语法

1.1 入口函数

        kotlin程序的入口是main函数(方法),下面是一个最简单的main函数,程序将从这里开始执行:

fun main() {
	println("Hello, world!")
}

        fun是声明方法的关键字,println是一个打印语句。main方法也可带输入参数:

fun main(args:Array<String>) {
	println("Hello, world!")
}

        kotlin每个语句后可以不加分号,如果多个语句写在同一行,需要用分号隔开,但并不推荐将多个语句写在一行。

       

       

1.2 输出

        输出可以用print()或println()方法,两者的区别是,print()打印后光标不会移动到下一行,println()打印后光标会移动到下一行(多个换行)。

fun main() {
	print("Hello,")
	print("world!")
	// 输出
	// Hello,world!
}
fun main() {
	println("Hello,")
	println("world!")
	// 输出
	// Hello,
	// world!
}

       

       

1.3 对象数据类型

        kotlin中对象数据类型的首字母是大写的,比如Int,但在java和c++中基本数据类型首字母是小写的。两者的差距并不是首字母大小写这么简单,kotlin中Int变成了一个类,它拥有自己的方法和继承结构。

Double双精度浮点型,8字节
Long长整型,8字节
Float单精度浮点型,4字节
Int整型,4字节
Short短整型,2字节
Byte字节
Boolean布尔型
Char字符型

       

       

1.4 变量和常量

        关键字var用于定义变量,关键字val用于定义常量。定义格式如下:

fun main() {
	val whole: Int = 11 			
	var fractional: Double = 1.4    
	val trueOrFalse: Boolean = true 
	var words: String = "A value"   
	val character: Char = 'z' 
	val lines: String = """Triple quotes let
							you have many linesin your string"""
}

也可以不写数据类型,编译器会做类型推断:

fun main() {
	val whole = 11 
	var fractional = 1.4 
	val trueOrFalse = true 
	var words = "A value" 
	val character = 'z' 
	val lines = """Triple quotes let
				you have many linesin your string"""
}

       

       

1.5 方法(函数)

函数定义基本格式:

fun functionName(p1: Type1, p2: Type2, ...): ReturnType {
	lines of code
	return result
}

        以关键字fun开头,然后是函数名,括号里是入参p1,p2,入参的数据类型是Type1,Type2,括号外是返回值类型ReturnType。
       下面是一个加法程序示例:

// 加法程序
fun add(x: Int,y:Int): Int { 
	return x + y
}
// 主函数
fun main() {
val r = add(5,7) 
println(r)
}

        当函数没有返回值时,返回值类型写成Unit,Unit可以省略不写,示例如下:

fun sayHello() {			// 可以省略Unit
	println("Hallo!")
}
fun sayGoodbye(): Unit {	// 可以写
	println("Auf Wiedersehen!")
}

       

       
        以上用大括号包围的函数体称为block body。当函数体非常简单,比如只有一个表达式时,可以写成=表达式的格式,这种称为expression body

// 这是一个计算3倍x的值的函数,函数体可以写成 =x*3
fun multiplyByThree(x: Int): Int = x * 3

       当函数体为expression body时,可以省略返回值类型,编译器会自动推断返回值类型:

// 这是一个计算3倍x的值的函数,省略了返回值类型
fun multiplyByThree(x: Int) = x * 3

       

       
        kotlin可以给函数设定默认参数值,例如:

fun funOne(int:Int=100,str:String,double: Double=0.7){
    println("测试")
}

fun main(){
    funOne(str="hh")
}

        调用函数时,用这种参数名=参数值的方式传值,传入参数的顺序谁前谁后都无所谓,因为kotlin可以根据参数名将参数准确地匹配上。
       

       

1.6 条件语句if

        使用方法与C++和Java相同,示例如下:

fun main() {
	val n: Int = -11
	if (n > 0)
		println("正数")
	else if (n == 0)
		println("0")
	else
		println("负数")
}

        在函数中,当函数体为expression body时,通常可以用if表达式得到返回值,不需要写“return”关键字。(这一点与c++和java不同,它们的if语句是没有返回值的,而kotlin的if语句可以有返回值):

fun checkSign(number: Int): String =
        if (number > 0)
            "正数"		// 不需要写return
        else if (number == 0)
            "0"
        else 
        	"负数"

fun main() {
    println(checkSign(-19))  
}

       

       

1.7 条件语句when

        kotlin中的when语句功能类似于c++和java中的switch语句。根据姓名返回得分的函数如下:

fun getScore(name:String)=when(name){
    "tom"->90
    "lily"->92
    "jack"->85
    else->0
}

        when语句还有一种不带参数的写法,这种写法有时能发挥很强的扩展性。仍是上面这个例子,假设所有名字以tom开头的人得分都是90分,代码如下:

fun getScore(name:String)=when{
    name.startsWith("tom")->90
    name=="lily"->92
    name=="jack"->85
    else->0
}

       

       

1.8 字符串与$

       在字符串中,符号"$"后接变量名时,效果是在字符串中插入变量的值,示例如下:

fun main() {
	val answer = 42
	println("Found $answer!") // 输出 Found 42!,answer被替换成了它的值
	println("printing a $1")  // 输出printing a $1,因为1不是变量名,所以不会有特殊的操作
}

        在${ }中放入一个表达式时,这个表达式执行后得到的值就会转换成字符串,示例如下:

fun main() {
	val condition = true
	println("${if (condition) 'a' else 'b'}") // 表达式if (condition) 'a' else 'b'执行后得到'a',转换成字符串"a",并打印出来
}

       当想使用一些特殊字符时,可以用反斜杠\\去掉其本身含义,例如:

fun main() {
	val str = "value"
	println("s = \\"$str\\".") // 反斜杠去掉了两个双引号的 特殊含义,最后输出s = "value".
	println("""s = "$s".""") // 也可使用三个双引号,最后输出s = "value".
}

       

       

1.9 循环语句while

        使用方法与C++和Java相同,示例如下:

var i = 0
while (i < 4) {   // 输出....
	print(".") 
	i++
}

       

       

1.10 循环语句for与关键字in

        使用方法与C++和Java不同。
        kotlin在访问一个区间或容器中的内容时,使用关键字in。例如要循环打印区间[1,3]范围内的数:

for (i in 1..3) {
	println("$i")
}
// 输出:
// 1
// 2
// 3

       
        区间的表示方法有多种,除了能正向步进外,还能反向步进,也就是例如9~1这样由大到小的区间。此外,除了以1步进外,还能用step指定步进大小,示例如下:

fun main() {
	val range1 = 1..5 		 // 区间[1,5],1 2 3 4 5
	val range2 = 1 until 5   // 区间[1,9),用until定义的区间是左闭右开的,1 2 3 4
	val range3 = 5 downTo 1  // 反向步进,5 4 3 2 1
	val range4 = 0..9 step 2        // 区间[0,9],以2步进,0 2 4 6 8
	val range5 = 0 until 10 step 3  // 区间[0,10],以3步进,0 3 6 9
	val range6 = 9 downTo 2 step 3  // 反向步进,以3步进,9 6 3
	println(range1)			// 打印这个区间范围内的所有数
}

       
        此外,除了整数能表示成区间外,字符也能,示例如下:

fun main() {
	for (c in 'a'..'z') {
		print(c)
	}
}

       
        in关键字除了能和for语句一起使用外, 还能用于判断一个值是否属于某个区间,例如:

fun main() {
	val i = 35
	println(i in 1..100)   // 等同于println(0 <= i && i <= 100),输出true
	
	var j:Double= 9.999
	println(j in 1.0..10.0)  // 输出true,需要注意的是,浮点数只能使用..表示区间,不能使用util
	
	println("ab" in "aa".."az")		// 输出 true
	println("ba" in "aa".."az")		// 输出 false
}

        上面代码中需要注意的是,浮点数只能使用…表示区间,不能使用util。

       

        又例如和if语句一起使用:

fun main() {
	if( 't' in "kotlin"){
		println("true")
	}
	if( 'a' !in "kotlin"){
		println("true")
	}
}
/* 输出:
true
true
*/

       

       

1.11 repeat()函数

        当要重复一个操作时,也可使用repeat(n)函数,n为重复次数,示例如下:

fun main() {
	repeat(2) {
		println("hi!")
	}
}
/* 输出:
hi!
hi!
*/

       
       

       

2 面向对象编程

2.1 类与对象

        定义类的方式与c++类似,假设现在定义一个类表示人,程序实例如下:

class Person {
    var name =""
    var age=0
    fun eat(){
        println("$name is eating. She/he is $age years old")
    }
}

       实例化一个类,并给这个类的数据成员赋值:

fun main(){
    val p=Person()
    p.name="xiaoWang"
    p.age=25
    p.eat()
}

       

       

2.2 继承

        c++和java中,一个类默认能被继承,但kotlin中默认类是不能被继承的,如果一个类能被其他类继承,需要在这个类前加上open关键字,主动告诉编译器这个类可以被继承。仍是上面这个例子,程序示例如下:

open class Person {
    var name =""
    var age=0
    fun eat(){
        println("$name is eating. She/he is $age years old")
    }
}

       使Student类继承于Person类,不同于c++的是,在继承时Person后加上了一对括号:

class Student:Person() {
    var id=""
    var score=0
    fun getScore(){
        println("id:$id  score:$score")
    }
}

       

       

2.3 构造函数

        kotlin将构造函数分成了两种,主构造函数和次构造函数,一个类只有一个主构造函数,但可以有很多个次构造函数。每个类都默认有一个不带参数的主构造函数,例如前面的Person类,用val p=Person()实例化。

       如果要显式的给Student的主构造函数指明参数,程序示例如下:

class Student(id:String,score:Int):Person() {
    var id=""
    var score=0
    fun getScore(){
        println("id:$id  score:$score")       
    }
 }

       此时要实例化类Student,必须带参数:

val xiaoWang = Student("0303",87)

       主构造函数的特点是没有函数体,如果想在主构造函数中写一些代码,可以用init结构体:

class Student(id:String,score:Int):Person() {
    init {  // 主构造函数的函数体
        println("id:$id")
        println("score:$score")
    }
    var id=""
    var score=0
    fun getScore(){
        println("id:$id  score:$score")
    }
}

        和c++、java一样,子类的构造函数必须调用父类的构造函数。kotlin中有主构造函数和次构造函数,子类要调用父类的哪个构造函数,需要在继承时指定。例如class Student(id:String,score:Int):Person() 就调用了Person类的默认构造函数Person()。

       

        次构造函数用关键字constructor来定义:

class Student(id:String, score:Int, name: String, age: Int):Person(name, age) {
    constructor(id: String,score: Int) : this("",0,name, age) {
        println("id:$id  score:$score")
    }
    constructor():this("",0){

    }
    var id=""
    var score=0
    fun getScore(){
        println("id:$id  score:$score")
    }
}

       以上代码IDE报错“There’s a cycle in the delegation calls chain“,待解决,还没想明白。
       

       

       

2.4 接口

        kotlin中的接口和java几乎是完全一致的。c++允许多继承,而java中是禁止多继承的,一个类最多只能继承于一个父类,但却可以实现多个接口。

        这里说一下java中抽象类和接口类的区别:抽象类中除了可以有抽象方法外,还可以有数据成员和普通成员方法,接口也可以有数据成员和方法,但接口中的方法必须都是抽象方法。

        这里举的例子是,基类是Person,Study是接口,Student继承于Person和Study:

open class Person() { // 使用open关键字,使该类可以被继承
    var name =""
    var age=0
    fun eat(){
        println("$name is eating. She/he is $age years old")
    }
}
interface Study {      // 使用interface关键字定义接口
    fun readBooks()    // 接口中的函数没有函数体
    fun doHomework(){  // 如果有了函数体,那么函数体中的内容就是这个函数默认的实现,其他类继承这个接口后,不是必须实现这个函数
        println("这是doHomework()函数的默认实现")
    }
}
class Student(id:String, score:Int):Person() ,Study{
    var id=""
    var score=0
    fun getScore(){
        println("id:$id  score:$score")
    }

    override fun readBooks() {
       println("read books")
    }

    // 由于接口中的这个函数有默认实现,所以这里可以选择实现或者不实现这个函数,如果不实现,使用的就是这个函数在接口中的默认实现
    override fun doHomework() {  
        println("do homework")
    }
}

       

       

       

2.5 可见修饰符

public所有类可见
private当前类可见
protected当前类、子类可见
internal同一模块中的类可见

       

       

2.6 数据类与单例类

        创建数据类使用关键字data,创建一个手机数据类的实例如下:

data class Cellphone(val price:Double)

        kotlin会自动根据主构造函数中的参数将equals()、hashCoad()、toString()等方法写好,而在java中,通常还需要自己重写这些方法。
       

        kotlin中创建单例类也很方便,不需要自己讲构造函数写成私有然后在写一个getInstance()的方法获取实例,只需要讲class关键字换成object关键字即可:

object Singleton{ // 这就是一个单例类了
}

       
       

       

3 空值检查

        c++和java中都可能因为空值产生异常,例如:

public void doStudy(Study study){
	study.readBooks();
	study.doHomework()
}

        上面的代码,如果study是null,就会发生空指针异常。kotlin中任何变量和参数都是默认不为空的,kotlin会在编译时就检查空值,如果程序存在空值的风险,编译就通不过。如下的kotlin代码是安全的:

fun doStudy(study:Study){
    study.readBooks()
    study.doHomework()
}
fun main(){
    val xiaoWang=Student("0303",87)
    doStudy(xiaoWang)
}

        如果传入空值,IDE会在你编辑代码的时候就提示错误。
在这里插入图片描述
       

       

3.1 ? 与 ?. 与 ?:

        如果一个变量可能为空,需要显式地用符号“?”和“?.”指定,例如:

fun doStudy(study:Study?){  // 类型后加上问号?,表示可以为空
    study?.readBooks()      // 使用?. ,当对象不为空时正常调用,当对象为空时什么都不做。
    study?.doHomework()
}

fun main(){
    val n=null
    doStudy(null)
}

     

以上是关于Kotlin快速入门:基础语法类与继承集合的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin学习—— 基础巩固,类与继承,Lambda,表达式,计算器

kotlin入门

Kotlin类与继承

Python基础知识详解 从入门到精通类与对象

荐书 | Kotlin开发快速入门与实战

Scala入门学习之包类与对象