Kotlin學習快速入門(3)——類 繼承 介面

one發表於2019-07-29

參考連結

類定義格式

使用class關鍵字定義,格式如下:

class T{
    //屬性
    //建構函式
    //函式
    //內部類
}

Java Bean類

java bean類

//java bean類
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

java bean類(kotlin實現)

//kotlin寫法,get和set方法預設實現
class Student {
    /注意,這裡的var代表著變數的數值之後可以被修改,也可以使用只讀val
    //?是可為空的寫法,後面會提到
    //這裡其實包含了主構造方法,不過因為主構造方法為空,所以省略了
    var name: String? = null
    var age: Int = 0

    //這幾個constructor是次級構造方法
    constructor() {}

    constructor(name: String) {
        this.name = name
    }

    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }
    
}

//下面是沒有省略主構造方法的
//注意,因為把預設的主構造方法寫了出來,所以,不允許出現無引數的次構造方法
class Student public constructor() {
    //注意,這裡的var代表著變數的數值之後可以被修改,也可以使用只讀val
    //?是可為空的寫法,後面會提到
    //這裡其實包含了主構造方法,不過因為主構造方法為空,所以省略了
    var name: String? = null
    var age: Int = 0

    //這幾個constructor是次級構造方法
    constructor(name: String) : this() {
        this.name = name
    }

    constructor(name: String, age: Int)  : this(){
        this.name = name
        this.age = age
    }
}

主函式呼叫

//主函式呼叫
fun main(args: Array<String>){
    //宣告類不需要new關鍵字
    val student = Student("star",12)
    //,使用物件.屬性名呼叫,而不是使用get或set
    println(student.age)//獲得屬性
    student.name = "stars"//修改屬性
}

主構造方法(kotlin)

kotlin類中可以有主構造方法和次構造方法,次構造方法也就是上面那段使用kotlin實現的Java Bean類(上面的主構造方法其實是省略了的)

/*下面三種方法都是宣告瞭一個Student類
*Student包含了一個構造方法(兩個引數),還有兩個成員變數以及成員變數對應的get和set方法
*/

//原始方式,使用主構造方法
class Student public constructor(name: String,age: Int) {
    //注意,這裡的var代表著變數的數值之後可以被修改,也可以使用只讀val
    var name = name
    var age = age
}

//簡潔寫法,如果主構造方法只有預設的修飾符(public,預設的修飾符可省略),可以把constructor省略
class Student(name: String,age: Int) {
    var name = name
    var age = age
}

//更簡潔寫法
class Student(var name: String,var age: Int) {
}

//使用Student類
fun main(args: Array<String>) {
    //宣告類不需要new關鍵字
    val student = Student("star",12)
    println(student.name)
    println(student.age)
    student.age = 19 //修改內容
    println(student.age)
}

init(初始化塊)

如果我們想要在主構造方法進行初始化操作,需要在init程式碼塊裡面寫我們的程式碼,如

//更簡潔寫法
class Student(var name: String,var age: Int) {
    init{
        println("這裡是初始化操作")
    }
}

注意,初始化塊是主構造方法的一部分

初始化操作會在次構造方法之前執行,即使沒有寫主構造方法,如:

class Student{
    var name: String? = null
    var age: Int = 0
    
    init{
        println("這裡是初始化操作")
    }
    
    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }
}

主/次構造方法聯合使用

類定義了主構造器,次構造器必須直接或間接呼叫主構造器;

class Student() {
    var name: String? = null
    var age: Int = 0

    //這幾個constructor是次級構造方法,,這裡的this()就是當前的主構造方法
    constructor(name: String) : this() {
        this.name = name
    }

    constructor(name: String, age: Int)  : this(){
        this.name = name
        this.age = age
    }
}
class Student public constructor() {
    var name: String? = null
    var age: Int = 0

    //這幾個constructor是次級構造方法,,這裡的this()就是當前的主構造方法
    //這裡用專業術語說,是次級構造方法需要委託給主構造方法
    constructor(name: String) : this() {
        this.name = name
    }

    constructor(name: String, age: Int)  : this(){
        this.name = name
        this.age = age
    }
}

伴生方法(靜態方法)

class Student{
    ...
    companion object {
        @JvmStatic
        //下面定義一些方法
        fun sayHello() {
            println("hello")
        }
    }
}

get/set方法修改

看完上面,我們都知道kotlin預設幫我們實現了get和set方法,val修飾的變數是隻讀的,所以該變數沒有setter方法

格式:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]
//表示式寫法
get() = ...
//花括號寫法
get(){
    ...
    return xx
}   
class Student() {
    var name: String = ""
    var age: Int = 0
    //這裡使用val
    val isNameEmpty: Boolean
        get() = name.length==0
 
    //使用var就得賦值
    //val isNameEmpty: Boolean
    //    get() = name.length==0
    
    constructor(name: String) : this() {
        this.name = name
    }

    constructor(name: String, age: Int)  : this(){
        this.name = name
        this.age = age
    }
}

如果要在get和set引用當前的欄位(屬性值),得使用filed關鍵字代替內容

class Student() {
    var name: String = ""
        //如果當前的name為"",則返回小紅作為姓名
        //這裡的filed就是name,型別也與name一樣
        get() {
            return if(field.length==0) "小紅" else field
        }
    var age: Int = 0

    constructor(name: String) : this() {
        this.name = name
    }

    constructor(name: String, age: Int)  : this(){
        this.name = name
        this.age = age
    }
}

setter方法與之前的getter方法一樣,裡面也是使用field代替當前的數值,只不過setter有一個引數,預設為value,可以修改名字

set(value){
    filed = vaule
}

巢狀類和內部類

巢狀類和內部類的區別是,巢狀類無法引用外層類的屬性和方法,而內部類可以

//Nested為巢狀類
class Outer {
    private val bar: Int = 1
    class Nested {
        //這裡因為是巢狀類,無法引用Outer中的bar
        fun foo() = 2
    }
}

val demo = Outer.Nested().foo() // == 2

內部類,使用inner關鍵字

class Outer {
    private val bar: Int = 1
    inner class Inner {
        //這裡可以引用bar
        fun foo() = bar
    }
}

val demo = Outer().Inner().foo() // == 1

繼承和介面

繼承

kotlin所有的類都是繼承於Any,注意,Any 並不是 java.lang.Object

kotlin中的類預設是不可繼承的,需要有open關鍵字修飾類,需要在子類複寫的方法,也得在父類用open修飾該方法

open class Person{
    var name: String = ""
    var age: Int =0
    
    constructor(){}
    constructor(name: String, age: Int){
        this.name = name
        this.age = age
    }

    open fun hello() {
        println("hello this is person")
    }
}

class Student: Person {
    constructor() : super(){}
    constructor(name: String,age: Int) :super(name,age){}

    override fun hello() {
        println("hello this is student")
    }
}

介面

介面的實現也是使用:,宣告介面也是interface關鍵字,注意,kotlin中的介面方法可以實現

interface Print {
    fun print()
    fun say(){
        println("sayhello")
    }
}

Student類繼承Person並實現Print介面:

class Student: Person,Print {
    override fun print() {
        //複寫介面裡的方法
    }

    constructor(name: String,age: Int) :super(name,age){}

    override fun hello() {

    }
}

資料類

介紹

kotlin提供了一個資料類,專門類存放資料,使用關鍵字data修飾類

官方的關於資料類的規範:

  • 主建構函式需要至少有一個引數;
  • 主建構函式的所有引數需要標記為 val 或 var;
  • 資料類不能是抽象、開放、密封或者內部的;
  • (在1.1之前)資料類只能實現介面。

資料類主要有下面兩種特點:

  • 自動解析
  • 直接複製

資料類定義

data class Person(var name: String,var age: Int){
}

自動解析

自動解析有順序,根據類中屬性的屬性

val person = Person("star",19)
//val括號裡可以根據需要選擇不同引數,注意順序,不能跳過一個不需要的屬性
val(name,age) = person
println("$name, $age years of age") // 輸出 "star, 19 years of age"

複製

val person = Person("star",19)
val person1 = person.copy()
//複製並修改部分屬性
val person2 = person.copy(age =23)

總結

個人覺得,如果某個類只有一個構造方法,可以定義類只含有一個主構造方法即可,使用那個最簡潔的方式。

如果需要有不同引數的構造方法(或者是Java Bean),則使用次級構造方法

如果是用來當做資料類,則使用資料類定義

相關文章