一、 变量和函数
1.1 变量
Kotlin定义变量,只允许在变量前声明两种关键字:val 和 var
- val(value 的简写)用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能重新赋 值,对应 Java 中的 final 变量。
- var(variable 的简写)用来声明一个可变的变量,这种变量在初始赋值之后仍然可以再被重新赋值,对应 Java 中的非 final 变量。
kotlin有十分优秀的类型推导机制,你可以不声明变量的类型。
但是如果你使用延迟赋值的话,kotlin的推导机制可能无法正常工作,为此,应该养成显式声明变量类型的习惯:
var number : Int = 10
以上代码含义为:声明了一个Int类型的可变变量number,并为它赋值10。
_* 没错,kotlin中的变量类型和Java的区别就是首字母大写。kotlin放弃使用基本类型,而是使用了Java包装类一样的对象数据类型。 *_
1.2 函数
首先,我们来看一段代码:
fun largerNumber(num1: Int, num2: Int): Int {
return max(num1, num2)
}
emmm…
kotlin定义一个方法(函数)必须使用 fun 关键字;下面详细分析一下
largerNumber 方法名
num1:Int 参数名 :参数类型型
Int 返回值类型
上面是最基础的函数表达式,后续有更复杂的再讲。
在Lambda 盛行的今天,来看看Kotlin可以怎么做:
当一个函数中只有一行代码时,我们不必编写函数体,可以直接将唯一的一行代码写在函数定义的尾部,中间用等号连接即可 。
fun largerNumber(num1: Int, num2: Int): Int = max(num1, num2)
既然kotlin有自己的推导机制,所以返回值类型也可以省略。 ```kotlin fun largerNumber(num1: Int, num2: Int) = max(num1, num2)
- 如果使用public 方法,则必须明确写出返回类型
```kotlin
public fun sum(a: Int, b: Int): Int = a + b
- 如果返回值为空,可以有以下几种写法: ```kotlin fun printSum(a: Int, b: Int): Unit { print(a + b) }
// 如果是返回 Unit类型,则可以省略(对于public方法也是这样): public fun printSum(a: Int, b: Int) { print(a + b) }
- 可变参数,用 `**vararg** `关键字进行标识
```kotlin
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
lambda(匿名函数)
fun main(args: Array<String>) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 输出 3
}
二、程序的逻辑控制
2.1 if条件语句
首先看一下大众的写法: ```kotlin fun largerNumber(num1: Int, num2: Int): Int { var value = 0 if (num1 > num2) {
value = num1
} else {
value = num2
} return value }
- kotlin追加了一个特性,使得 if 能够返回值
```kotlin
fun largerNumber(num1: Int, num2: Int): Int {
val value = if (num1 > num2) {
num1
} else {
num2
}
return value
}
这样一来,value就显得有点多余,我们把它去除
fun largerNumber(num1: Int, num2: Int): Int {
return if (num1 > num2) {
num1
} else {
num2
}
}
一行语句?那么语法糖(Lambda)来了
fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) {
num1
} else {
num2
}
括号显得有点多余,进行精简 ```kotlin fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) num1 else num2
<a name="ByXGV"></a>
## 2.2 when 语句
when语句允许传入任意类型的参数,然后在结构提中定义一系列条件。<br />` 匹配值 -> { 执行逻辑 } `
- 小试牛刀一下
```kotlin
fun getScore(name: String) = when (name) {
"Tom" -> 86
"Jim" -> 77
"Jack" -> 95
"Lily" -> 100
else -> 0
}
除了以上这种精准匹配的方式外。kotlin还支持类型匹配
fun checkNumber(num: Number) {
when (num) {
is Int -> println("number is Int")
is Double -> println("number is Double")
else -> println("number not support")
}
}
when 也可以不填入判断参数,以此做某些更骚气的操作:如下代码中,当name为Tom开头时,返回86
fun getScore(name: String) = when {
name.startsWith("Tom") -> 86
name == "Jim" -> 77
name == "Jack" -> 95
name == "Lily" -> 100
else -> 0
}
2.3 循环语句
Java中的for-i循环被kotlin舍弃,for-each循环被增强为for-in。
val range = 0..10
表示一个区间[0,10]val range = 0 until 10
表示一个左闭右开的区间 [0,10) val range = 10 downTo 1
表示一个降序区间[10,1]
- 简单写法
fun main() {
for (i in 0..10) {
println(i)
}
}
- 使用步长 step 关键字 ```kotlin fun main() { for (i in 0 until 10 step 2) { println(i) } }
- 使用降序 downTo 关键字
```kotlin
fun main() {
for (i in 10 downTo 1) {
println(i)
}
}
三、 面向对象编程
3.1类和对象
3.1.1 类定义
class 关键字声明类
class Runoob {
...
}
定义一个空类
class Empty
3.1.2 类的属性
属性定义
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
getter和setter
class Person {
var lastName: String = "zhang"
get() = field.toUpperCase() // 将变量赋值后转换为大写
set
var no: Int = 100
get() = field // 后端变量
set(value) {
if (value < 10) { // 如果传入的值小于 10 返回该值
field = value
} else {
field = -1 // 如果传入的值大于等于 10 返回 -1
}
}
var heiht: Float = 145.4f
private set
}
Kotlin 中类不能有字段。提供了 Backing Fields(后端变量) 机制,备用字段使用field关键字声明,field 关键词只能用于属性的访问器。如上。
非空属性必须在定义的时候初始化,kotlin提供了一种可以延迟初始化的方案,使用 lateinit 关键字描述属性
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // dereference directly
}
}
创建实例
val site = Runoob() // Kotlin 中没有 new 关键字
属性引用 ```kotlin site.name // 使用 . 号来引用 site.url
<a name="mZzn6"></a>
### 3.1.3 主构造器
主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init 关键字作为前缀。
```kotlin
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
主构造器的参数可以在初始化代码段中使用,也可以在类主体n定义的属性初始化代码中使用。可以通过主构造器来定义属性并初始化属性值(可以是var或val)
创建一个 Runoob类 ```kotlin class Runoob constructor(name: String) { // 类名为 Runoob // 大括号内是类体构成 var url: String = “http://www.runoob.com“ var country: String = “CN” var siteName = name
init {
println("初始化网站名: ${name}")
}
fun printTest() {
println("我是类的函数")
} }
<a name="osNSu"></a>
### 3.1.4 次构造函数
类也可以有二级构造函数,需要加前缀 constructor;<br />如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字
```kotlin
class Person(val name: String) {
constructor (name: String, age:Int) : this(name) {
// 初始化...
}
}
class Runoob constructor(name: String) { // 类名为 Runoob
// 大括号内是类体构成
var url: String = "http://www.runoob.com"
var country: String = "CN"
var siteName = name
init {
println("初始化网站名: ${name}")
}
// 次构造函数
constructor (name: String, alexa: Int) : this(name) {
println("Alexa 排名 $alexa")
}
fun printTest() {
println("我是类的函数")
}
}
3.1.5 类的修饰符
- 类属性修饰符
- abstract // 抽象类
- final // 类不可继承,默认属性
- enum // 枚举类
- open // 类可继承,类默认是final的
- annotation // 注解类
访问权限修饰符
抽象类 ```kotlin open class Base { open fun f() {} }
abstract class Derived : Base() { override abstract fun f() }
- 嵌套类
```kotlin
class Outer { // 外部类
private val bar: Int = 1
class Nested { // 嵌套类
fun foo() = 2
}
}
fun main(args: Array<String>) {
val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
println(demo) // == 2
}
- 内部类
```kotlin
class Outer {
private val bar: Int = 1
var v = “成员属性”
/嵌套内部类/
inner class Inner {
} }fun foo() = bar // 访问外部类成员
fun innerTest() {
var o = this@Outer //获取外部类的成员变量
println("内部类可以引用外部类的成员,例如:" + o.v)
}
fun main(args: Array
println(demo2) // 内部类可以引用外部类的成员,例如:成员属性
}
- 匿名内部类
```kotlin
class Test {
var v = "成员属性"
fun setInterFace(test: TestInterFace) {
test.test()
}
}
/**
* 定义接口
*/
interface TestInterFace {
fun test()
}
fun main(args: Array<String>) {
var test = Test()
/**
* 采用对象表达式来创建接口对象,即匿名内部类的实例。
*/
test.setInterFace(object : TestInterFace {
override fun test() {
println("对象表达式创建匿名内部类的实例")
}
})
}
3.2 继承
Kotlin 中所有类都继承 Any 类,且提供三个方法
equals()
hashCode()
toString()
在kotlin中,任何一个非抽象类默认都是不能被继承的,除非加入 open 关键字。 遵循Java编程规范
- 定义一个可被继承的父类 Person
```kotlin
open class Person{
var name = “”
var age = 0
fun eat() {
}println(name + " is eating. He is " + age + " years old.")
}
与Java中的 extends 关键字不同的是,kotlin使用的是 : (冒号)。
- 定义一个继承了Person的子类Student
```kotlin
class Student : Person(){
var sno = ""
var grade = 0
}
3.2.1 重写
方法默认也是final的,如果允许子类重写,则需要加上open关键字。子类重写时加上override关键字。
/**用户基类**/
open class Person{
open fun study(){ // 允许子类重写
println("我毕业了")
}
}
/**子类继承 Person 类**/
class Student : Person() {
override fun study(){ // 重写方法
println("我在读大学")
}
}
fun main(args: Array<String>) {
val s = Student()
s.study();
}
- 如果是多继承的情况(接口等),有多个同名方法,可以使用super泛型进行区分。并且,为了消除歧义,子类也必须重写同名方法 ```kotlin open class A { open fun f () { print(“A”) } fun a() { print(“a”) } }
interface B { fun f() { print(“B”) } //接口的成员变量默认是 open 的 fun b() { print(“b”) } }
class C() : A() , B{ override fun f() { super.f()//调用 A.f() super.f()//调用 B.f() } }
fun main(args: Array
<a name="DSQ6I"></a>
### 3.2.2 属性重写
同理,实现属性重写也必须使用open和override关键字。重写的属性需要具有兼容性。<br />**可以使用var重写val,但不能使用val重写var,因为val本身定义了getter方法,重写为var会多出一个setter方法。**
<a name="c3cjh"></a>
## 3.3 接口
kotlin接口的写法和Java8类似,使用interface关键字定义,允许方法有默认实现。
```kotlin
interface MyInterface {
fun bar() // 未实现
fun foo() { //已实现
// 可选的方法体
println("foo")
}
}
- 接口实现
```kotlin
interface MyInterface {
fun bar()
fun foo() {
} } class Child : MyInterface { override fun bar() {// 可选的方法体
println("foo")
} } fun main(args: Array// 方法体
println("bar")
) { val c = Child() c.foo(); c.bar(); }
<a name="LwKO5"></a>
## 3.4 kotlin拓展
Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 Decorator 模式。
<br />扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响。
<a name="X1FzP"></a>
### 3.4.1 拓展函数
形式:
```kotlin
fun receiverType.functionName(params){
body
}
params:扩展函数的参数,可以为NULL
- receiverType:表示函数的接收者,也就是函数扩展的对象