Kotlin-基礎筆記整理一

1、方法的定義:
fun sum(a: Int, b: Int): Int {   // Int 參數a和b,返回值 Int
    return a + b
}
//表達式作為函數體,返回類型自動推斷
fun sum(a: Int, b: Int) = a + b
public fun sum(a: Int, b: Int): Int = a + b   // public 方法則必須明確寫出返回類型

fun printSum(a: Int, b: Int): Unit { 
    print(a + b)
}

//Unit相當于java中的void
// 如果是返回 Unit類型,則可以省略(對于public方法也是這樣):
public fun printSum(a: Int, b: Int) { 
    print(a + b)
}

可變長參數函數

fun vars(vararg v:Int){
    for(vt in v){
        print(vt)
    }
}

// 測試
fun main(args: Array<String>) {
    vars(1,2,3,4,5)  // 輸出12345
}

lambda(匿名函數)

// 測試
fun main(args: Array<String>) {
    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
    println(sumLambda(1,2))  // 輸出 3
}
2、常量與變量:

var和val的區別:
val:定義的變量是不可修改的(類似于java中的final)
var:定義的變量是可以修改的

常量與變量都可以沒有初始化值,但是在引用前必須初始化
編譯器支持自動類型判斷,即聲明時可以不指定類型,由編譯器判斷。

val a: Int = 1
val b = 1       // 系統自動推斷變量類型為Int
val c: Int      // 如果不在聲明時初始化則必須提供變量類型
c = 1           // 明確賦值
var x = 5        // 系統自動推斷變量類型為Int
x += 1           // 變量可修改
3、NULL檢查機制:

代碼中可為空的參數,使用時需要進行空判斷處理,2種處理方式
1、字段后加!!像Java一樣拋出空異常
2、字段后加?可不做處理,返回值為 null或配合?:做空判斷處理

任何對象都分為可null和不可null,當對象可以為null時,使用的時候必須加判斷,或者加上!!

fun main(args: Array<String>) {
//類型后面加?表示可為空
var age: String? = "23" 
//拋出空指針異常
val ages = age!!.toInt()
//不做處理返回 null
val ages1 = age?.toInt()
//age為空返回-1
val ages2 = age?.toInt() ?: -1
//-----------------------------------------------------------
    //使用
    val token = token()
    //第一種方法
    if (token != null) {//不加判斷會報錯
        println(token.length)
        //token?.length  //如果token為null,則token?.length返回null,不會報錯
    }
 //第二種方法,當token為null時,會拋出空異常
 //println(token!!.length) 
}
//聲明返回值可以為null
fun token(): String? {
    return null
}
4、類型檢測及自動類型轉換:

使用 is 運算符檢測一個表達式是否某類型的一個實例(類似于Java中的instanceof關鍵字)

fun getStringLength(obj: Any): Int? {
    if (obj !is String)
        return null
    // 在這個分支中, `obj` 的類型會被自動轉換為 `String`
    //---------------------------------------------------
    // 在 `&&` 運算符的右側, `obj` 的類型會被自動轉換為 `String`
    /*  if (obj is String && obj.length > 0)
          return obj.length*/
    //---------------------------------------------------
    return obj.length
}
5、區間:

區間表達式由具有操作符形式 .. 的 rangeTo 函數輔以 in 和 !in 形成

for (i in 1..4) print(i) // 輸出“1234”

for (i in 4..1) print(i) // 什么都不輸出

if (i in 1..10) { // 等同于 1 <= i && i <= 10
    println(i)
}

// 使用 step 指定步長
for (i in 1..4 step 2) print(i) // 輸出“13”

for (i in 4 downTo 1 step 2) print(i) // 輸出“42”

// 使用 until 函數排除結束元素
for (i in 1 until 10) {   // i in [1, 10) 排除了 10
     println(i)
}
6、比較數字:

Kotlin 中,三個等號 === 表示比較對象地址,兩個 == 表示比較兩個值大小

fun main(args: Array<String>) {
    val a: Int = 10000
    println(a === a) // true,值相等,對象地址相等

    //經過了裝箱,創建了兩個不同的對象
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    //雖然經過了裝箱,但是值是相等的,都是10000
    println(boxedA === anotherBoxedA) //  false,值相等,對象地址不一樣
    println(boxedA == anotherBoxedA) // true,值相等
}
7、類型轉換:
  val b: Byte = 1 // OK, 字面值是靜態檢測的
    //al i: Int = b // 錯誤
    val i: Int = b.toInt() // OK

toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char

8、數組:

數組的創建兩種方式:
1、一種是使用函數arrayOf()
2、另外一種是使用工廠函數。

fun main(args: Array<String>) {
    //[1,2,3]
    val a = arrayOf(1, 2, 3)
    //[0,2,4]
    val b = Array(3, { i -> (i * 2) })

    //讀取數組內容
    println(a[0])    // 輸出結果:1
    println(b[1])    // 輸出結果:2
}

除了類Array,還有ByteArray, ShortArray, IntArray,用來表示各個類型的數組

9、字符串:

和 Java 一樣,String 是不可變的

 var str = "1234";
    for (c in str) {//遍歷打印字符串
        println(c)
    }
    //----------------------------
    val text = """
    多行字符串
    多行字符串
    """.trimMargin()//去掉前置空格
10、條件控制:
fun main(args: Array<String>) {
    var x = 0
    if(x>0){
        println("x 大于 0")
    }else if(x==0){
        println("x 等于 0")
    }else{
        println("x 小于 0")
    }

    var a = 1
    var b = 2
    val c = if (a>=b) a else b
    println("c 的值為 $c")
}

使用區間

fun main(args: Array<String>) {
    val x = 5
    val y = 9
    if (x in 1..8) {
        println("x 在區間內")
    }
}
11、When 表達式:

when 將它的參數和所有的分支條件順序比較,直到某個分支滿足條件。

when 既可以被當做表達式使用也可以被當做語句使用。

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // 注意這個塊
        print("x 不是 1 ,也不是 2")
    }
}
//----------------------------------------
when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}
//-----------------------------------------
when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}
//----------------------------------------------
fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}
//----------------------------------------------
//用來取代if-else if
when {
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
}

在 when 中,else 等同 switch 的 default

12、循環控制:

For 循環

fun main(args: Array<String>) {
    val items = listOf("apple", "banana", "kiwi")
    for (item in items) {
        println(item)
    }

    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
}

while 與 do...while 循環

fun main(args: Array<String>) {
    println("----while 使用-----")
    var x = 5
    while (x > 0) {
        println( x--)
    }
    println("----do...while 使用-----")
    var y = 5
    do {
        println(y--)
    } while(y>0)
}
11、類的定義和類的屬性:
//constructor...主構造函數
//如果主構造器沒有任何注解,也沒有任何可見度修飾符,那么constructor關鍵字可以省略
class Person constructor(firstName: String) {
    var name: String = "張三"
}

fun main(args: Array<String>) {
    var person = Person("李四")//Kotlin 中沒有 new 關鍵字
    println("姓名:" + person.name)
}
  • getter 和 setter

getter 和 setter 都是可選
如果屬性類型可以從初始化語句或者類的成員函數中推斷出來,那就可以省去類型,val不允許設置setter函數,因為它是只讀的。

var allByDefault: Int? // 錯誤: 需要一個初始化語句, 默認實現了 getter 和 setter 方法
var initialized = 1    // 類型為 Int, 默認實現了 getter 和 setter
val simple: Int?       // 類型為 Int ,默認實現 getter ,但必須在構造函數中初始化
val inferredType = 1   // 類型為 Int 類型,默認實現 getter

示例:

class Person {
    var lastName: String = "zheng"
    //當調用person.lastName,獲取值field.toUpperCase()
    //field(后端變量)   toUpperCase將變量賦值后轉換為大寫
        get() = field.toUpperCase()
        set//當調用person.lastName = "wang",觸發set
    var no: Int = 100
        get() = field
        set(value) {//value當前傳遞過來的值,在賦值給field(后端變量)之前做一些操作改變值
            if (value < 10) {
                field = value  //傳入的值小于10返回改值
            } else {
                field = -1     //如果傳入的值大于等于10 返回-1
            }
        }
    var heiht: Float = 145.4f
        private set//set方法為私有是,外部不可調
}

fun main(args: Array<String>) {
    var person = Person()
    person.lastName = "wang"http://將wang賦值給lastName
    println("lastName:${person.lastName}")
    person.no = 9
    println("no:${person.no}")
}
  • 輸出
    lastName:WANG
    no:9

Kotlin 中類不能有字段。提供了 Backing Fields(后端變量) 機制,備用字段使用field關鍵字聲明,field 關鍵詞只能用于屬性的訪問器

  • 非空屬性必須在定義的時候初始化,kotlin提供了一種可以延遲初始化的方案,使用 lateinit 關鍵字描述屬性
 class MyTest {
    private lateinit var person: Person
    fun setUp() {
        person = Person("哇哈哈")
    }
    fun test() {
        println(person.name)
    }
}
fun main(args: Array<String>) {
    val myTest=MyTest()
    myTest.setUp()
    myTest.test()
}
  • 主構造器

主構造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中,初始化代碼段使用 init 關鍵字作為前綴

class Person constructor(firstName: String) {
    init {
        println("FirstName is $firstName")
    }
}

構造器有注解,或者有可見度修飾符,這時constructor關鍵字是必須的,注解和修飾符要放在它之前。

  • 次構造函數
    需要加前綴 constructor
class MyTest(name: String="") {
    var strName: String = ""
    var age: Int = 0
    init {
        strName = name
    }
    //同一個類中代理另一個構造函數使用 this 關鍵字
    constructor(name: String, age: Int) : this(name) {
        strName = name
        this.age = age
    }
    fun print() {
        println("strName" + strName + "-----age" + age)
    }
}
fun main(args: Array<String>) {
    val myTest1 = MyTest("傳遞給次構造函數", 20)
    myTest1.print()
    val myTest2 = MyTest("傳遞給主造函數")
    myTest2.print()
}
  • 輸出
    strName傳遞給次構造函數-----age20
    strName傳遞給主造函數-----age0

如果一個非抽象類沒有聲明構造函數(主構造函數或次構造函數),它會產生一個沒有參數的構造函數。構造函數是 public 。如果你不想你的類有公共的構造函數,你就得聲明一個空的主構造函數:

class DontCreateMe private constructor () {
}
12、抽象類和嵌套類:
  • 抽象類
open class Base {//open 標識此類可以被繼承
    open fun f() {}
}

abstract class Derived : Base() {
    override abstract fun f()
}

注意:無需對抽象類或抽象成員標注open注解

  • 嵌套類
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
}
13、內部類和匿名內部類:
  • 內部類
class Outer {
    private val bar: Int = 1
    var v = "成員屬性"

    /**嵌套內部類**/
    //類標記為inner,可以訪問外部類成員:
    inner class Inner {
        fun foo() = bar  // 訪問外部類成員

        fun innerTest() {
            var o = this@Outer //獲取外部類的對象
            println("內部類可以引用外部類的成員,例如:" + o.v)
        }
    }
}

fun main(args: Array<String>) {
    val demo = Outer().Inner().foo()
    println(demo) //   1
    val demo2 = Outer().Inner().innerTest()
    println(demo2)   // 內部類可以引用外部類的成員,例如:成員屬性
}

要訪問來自外部作用域的 this,我們使用this@label,其中 @label 是一個 代指 this 來源的標簽

  • 匿名內部類
class Test {
    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("對象表達式創建匿名內部類的實例")
        }
    })
}
14、類的修飾符:
  • classModifier: 類屬性修飾符,標示類本身特性。
abstract    // 抽象類  
final       // 類不可繼承,默認屬性
enum        // 枚舉類
open        // 類可繼承,類默認是final的
annotation  // 注解類
  • accessModifier: 訪問權限修飾符
private    // 僅在同一個文件中可見
protected  // 同一個文件中或子類可見
public     // 所有調用的地方都可見
internal   // 同一個模塊中可見
15、繼承:

Kotlin 中所有類都繼承該 Any 類,它是所有類的超類,對于沒有超類型聲明的類是默認超類

如果一個類要被繼承,可以使用 open 關鍵字進行修飾

open class Base(p: Int)           // 定義基類

class Derived(p: Int) : Base(p)
  • 子類有主構造函數
    則基類必須在主構造函數中立即初始化
open class Person2(var name : String, var age : Int){// 基類
}

class Student(name : String, age : Int, var no : String, var score : Int) : Person2(name, age) {//子類
}
  • 子類沒有主構造函數
    則必須在每一個二級構造函數中用 super 關鍵字初始化基類,或者在代理另一個構造函數。初始化基類時,可以調用基類的不同構造方法。
class Student : Person {
    constructor(ctx: Context) : super(ctx) {
    } 

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
    }
}
16、重寫:

在基類中,使用fun聲明函數時,此函數默認為final修飾,不能被子類重寫。如果允許子類重寫該函數,那么就要手動添加 open 修飾它, 子類重寫方法使用 override 關鍵詞:

/**用戶基類**/
open class Person{
    open fun study(){       // 允許子類重寫
        println("我畢業了")
    }
}
/**子類繼承 Person 類**/
class Student : Person() {
    override fun study(){    // 重寫方法
        println("我在讀大學")
    }
}

多個相同的方法(繼承或者實現自其他類,如A、B類),則必須要重寫該方法,使用super范型去選擇性地調用父類的實現。

  • 示例
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<A>.f()//調用 A.f()
        super<B>.f()//調用 B.f()
    }
}
fun main(args: Array<String>) {
    val c =  C()
    c.f();

}
  • 輸出
    AB
  • 屬性重寫
    使用 override 關鍵字,屬性必須具有兼容類型,每一個聲明的屬性都可以通過初始化程序或者getter方法被重寫:
interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容