Kotlin 進(jìn)階之路4 面向?qū)ο?/h2>

Kotlin 進(jìn)階之路 目錄

1.面向?qū)ο蚓幊?/h4>
  • 本質(zhì)上就是解決如何用程序描述世界的問(wèn)題
  • 討論如何把實(shí)際存在東西映射成程序的類和對(duì)象
  • 一種程序設(shè)計(jì)的思路、思想、方法
/**
 * 面向?qū)ο蚓幊? * 對(duì)某種事物進(jìn)行抽象化,稱之為建模
 *
 */

//kotlin 定義:class 類名 constructor(屬性列表){更多的屬性和方法描述}
//構(gòu)造器:用來(lái)設(shè)置類新實(shí)例的出廠配置

//類要被繼承需要加open
open class Chinese constructor(val sex: Boolean, var region: String) {
    //普通屬性,與變量定義相似
    open val skin = "yellow"

    //組合屬性,由其它屬性計(jì)算而來(lái)(get)
    val avgLife: Double
        get() {
            when (this.region) {
                    "Shanghai" -> {
                return 82.4
            }
                "Beijing" ->{
                    return 80.0
                }

                else -> {
                    return 72.1
                }
            }
        }
    //組合屬性反過(guò)來(lái)可以影響其它屬性(set,可選) this代表實(shí)例
    var avgSalary : Int
        get(){
            when(this.region){
                "Shanghai" ->{ return 4000}
                "Beijing" ->{ return 5100}
                else ->{ return 3500}
            }
        }
        set(value) {
            when (value) {
                in 4500..Int.MAX_VALUE -> {
                    this.region ="Beijing"
                }
                in 2800..4100->{
                    this.region ="Shanghai"

                }
                else -> {
                    this.region = "homeland"
                }
            }
        }

    //方法:廚藝
   open fun cook(): Unit {
        val meau = arrayOf("宮爆雞丁","番茄炒雞蛋","蔥爆牛肉")
        val desc = meau.reduce{s1,s2->s1+","+s2}
        println("我會(huì)${desc}")
    }
}

class BeijingPeople(sex: Boolean, region: String = "Beijing") : Chinese(sex, region) {

    val greatBuilding="the Forbidden City"
    //override覆蓋屬性好方法
    override val skin ="BeijingYellow"

    override fun cook() {
        super.cook()
        val meau = arrayOf("北京烤鴨","北京炸醬面","北京包子")
        val desc = meau.reduce{s1,s2->s1+","+s2}
        println("我還會(huì)${desc}")
    }
}

class ShanghaiPeople(sex: Boolean, region: String = "Shanghai") : Chinese(sex, region){
    val greatBuilding="the Oriental Pearl Tower"
    override val skin ="ShanghaiYellow"
    override fun cook() {
        super.cook()
        val meau = arrayOf("大閘蟹","小湯包","芝士焗面")
        val desc = meau.reduce{s1,s2->s1+","+s2}
        println("我還會(huì)${desc}")
    }
}

fun main(args: Array<String>) {
    //實(shí)例化一個(gè)類
    val Lili = BeijingPeople(true)
    Lili.avgSalary = 6000
    println(Lili.region)
    println(Lili.avgSalary)
    Lili.cook()

    println()
    val Jack = ShanghaiPeople(true)
    Lili.avgSalary = 5000
    println(Jack.region)
    println(Jack.avgSalary)
    Jack.cook()
}

Beijing
5100
我會(huì)宮爆雞丁,番茄炒雞蛋,蔥爆牛肉
我還會(huì)北京烤鴨,北京炸醬面,北京包子

Shanghai
4000
我會(huì)宮爆雞丁,番茄炒雞蛋,蔥爆牛肉
我還會(huì)大閘蟹,小湯包,芝士焗面

2.抽象類和接口

抽象類:理解為半成品
接口:類似于協(xié)議或者某種成品就有的功能

接口
  • 不能有狀態(tài)
  • 必須有類對(duì)其進(jìn)行實(shí)現(xiàn)后實(shí)現(xiàn)
  • 接口,直觀理解就是一種約定
   Kotlin的接口與Objective-C的Protocol比較類似
  • 舉例
interface InputDevice{
fun input(event: Any)
}
抽象類
  • 實(shí)現(xiàn)了一部分協(xié)議的半成品
  • 可以有狀態(tài),可以有方法實(shí)現(xiàn)
  • 必須由子類繼承后使用
抽象類和接口的共性
  • 比較抽象,不能直接實(shí)例化
  • 有需要子類(實(shí)現(xiàn)類)實(shí)現(xiàn)的方法
  • 父類(接口)變量可以接受子類(實(shí)現(xiàn)類)的實(shí)例賦值
抽象類和接口的區(qū)別
  • 抽象類有狀態(tài),接口沒(méi)有狀態(tài)
  • 抽象類有實(shí)現(xiàn)方法,接口只能有無(wú)狀態(tài)的默認(rèn)實(shí)現(xiàn)
  • 抽象類只能單繼承,接口可以多實(shí)現(xiàn)
  • 抽象類反應(yīng)本質(zhì),接口提現(xiàn)能力
interface InputDevice {
    fun input(event: Any)
}

interface USBInputDevice : InputDevice

interface BLEInputDevice : InputDevice

abstract  class USBMouse(val name:String) : USBInputDevice,OpticalMouse {
    override fun input(event: Any) {

    }

    override fun toString(): String {
        return name
    }
}
interface OpticalMouse{

}

class LogitechMouse:USBMouse("羅技鼠標(biāo)"){

}

class Computer {

    fun addUSBInputDevice(inputDevice: USBInputDevice) {
        //插入輸入設(shè)備
        println("add usb input device:$inputDevice")
    }

    fun addBLEInputDevice(inputDevice: BLEInputDevice) {
        //插入輸入設(shè)備
        println("add input device:$inputDevice")
    }

    fun addInputDevice(inputDevice: InputDevice) {
        when (inputDevice) {
            is BLEInputDevice -> {
                addBLEInputDevice(inputDevice)
            }
            is USBInputDevice -> {
                addUSBInputDevice(inputDevice)
            }
            else -> {
                throw IllegalArgumentException("輸入設(shè)備不支持")
            }
        }
    }
}

fun main(args: Array<String>) {
    val computer = Computer()
    val mouse = LogitechMouse()
    computer.addInputDevice(mouse)
}
add usb input device:羅技鼠標(biāo)

3.繼承(實(shí)現(xiàn))

繼承(實(shí)現(xiàn))語(yǔ)法要點(diǎn)
  • 父類需要open才可以被繼承
  • 父類方法、需要open才可以被覆寫(xiě)
  • 接口、接口方法、抽象類默認(rèn)為open
  • 覆寫(xiě)父類(接口)成員需要override關(guān)鍵字
  • class D:A(),B,C
  • 注意繼承類時(shí)實(shí)際上調(diào)用了父類的構(gòu)造方法
  • 類只能單繼承,接口可以多實(shí)現(xiàn)
接口代理
  • class Manager(driver:Driver):Driver by driver
  • 接口方法實(shí)現(xiàn)交給代理類實(shí)現(xiàn)
接口方法沖突
  • 接口方法可以有默認(rèn)實(shí)現(xiàn)
  • 簽名一致且返回值有沖突
  • 子類(實(shí)現(xiàn)類)必須覆寫(xiě)沖突方法
  • super<[父類(接口)名]>.方法名
abstract class Person(open val age: Int) {
    open fun work() {

    }
}

class Coder(age: Int) : Person(age) {
    override val age: Int
        get() = 0

    override fun work() {
        super.work()
        println("我是程序員")
    }
}

class Doctor(override val age: Int) : Person(age) {
    override fun work() {
        super.work()
        println("我是醫(yī)生")
    }
}

fun main(args: Array<String>) {
    val person = Coder(28)
    person.work()
    println(person.age)
    val person2 = Doctor(25)
    person2.work()
    println(person2.age)
}

我是程序員
0
我是醫(yī)生
25
class Manager : Driver, Writer {
    override fun write() {

    }

    override fun drive() {

    }
}

//寫(xiě)法一
//class SeniorManager(val driver: Driver,val writer: Writer):Driver,Writer{
//    override fun drive(){
//        driver.drive()
//    }
//    override fun write(){
//        writer.write()
//    }
//}
//簡(jiǎn)寫(xiě)二
class SeniorManager(val driver: Driver, val writer: Writer) : Driver by driver, Writer by writer

class CarDriver : Driver {
    override fun drive() {
        println("開(kāi)車了")
    }
}
class PPTWriter :Writer{
    override fun write(){
        println("做PPT了")
    }
}

interface Driver {
    fun drive() {

    }
}

interface Writer {
    fun write() {
    }
}

fun main(args: Array<String>) {
    val driver = CarDriver()
    val writer = PPTWriter()
    val seniorManager = SeniorManager(driver,writer)
    seniorManager.drive()
    seniorManager.write()
}
開(kāi)車了
做PPT了
interface InputDevice {
    fun input(event: Any)
}

interface USBInputDevice : InputDevice

interface BLEInputDevice : InputDevice

abstract  class USBMouse(val name:String) : USBInputDevice,OpticalMouse {
    override fun input(event: Any) {

    }

    override fun toString(): String {
        return name
    }
}
interface OpticalMouse{

}

class LogitechMouse:USBMouse("羅技鼠標(biāo)"){

}

class Computer {

    fun addUSBInputDevice(inputDevice: USBInputDevice) {
        //插入輸入設(shè)備
        println("add usb input device:$inputDevice")
    }

    fun addBLEInputDevice(inputDevice: BLEInputDevice) {
        //插入輸入設(shè)備
        println("add input device:$inputDevice")
    }

    fun addInputDevice(inputDevice: InputDevice) {
        when (inputDevice) {
            is BLEInputDevice -> {
                addBLEInputDevice(inputDevice)
            }
            is USBInputDevice -> {
                addUSBInputDevice(inputDevice)
            }
            else -> {
                throw IllegalArgumentException("輸入設(shè)備不支持")
            }
        }
    }
}

fun main(args: Array<String>) {
    val computer = Computer()
    val mouse = LogitechMouse()
    computer.addInputDevice(mouse)
}
add usb input device:羅技鼠標(biāo)

4.Kotlin和Java可見(jiàn)性對(duì)比

Kotlin Java
public public
private priavte
protected protected
- default(包內(nèi)可見(jiàn))
internal(模塊類可見(jiàn)) -

5.對(duì)象聲明和表達(dá)式

object
  • 只有一個(gè)實(shí)例的類
  • 不能自定義構(gòu)造方法
  • 可以實(shí)現(xiàn)接口、繼承父類
  • 本質(zhì)上就是單例模式最基本的實(shí)現(xiàn)
/**
 * 有時(shí)候只要對(duì)某各類進(jìn)行改造,供零時(shí)使用,避免繼承
 * 對(duì)象聲明和表達(dá)式就很有作用
 *
 * 面向?qū)ο缶幊痰膬?yōu)化,避免一些繼承導(dǎo)致的代價(jià)過(guò)高,保持代碼的整潔
 */


//對(duì)中國(guó)人來(lái)說(shuō),這個(gè)類,可能各省人適合繼承
open class Chinese(var name: String) {

    open val skin = "yellow"
}

fun main(args: Array<String>) {
    //但如果外國(guó)人入籍,就不適合用繼承
    //對(duì)象表達(dá)式:val 對(duì)象名 = object : 類,接口 {//屬性或方法的override定義}

    val Jack= object : Chinese ("Jack Marry")
    {
        override val skin = "white"
    }

    println(Jack.skin)

    //純對(duì)象表達(dá)式:臨時(shí)使用,無(wú)須繼承任何類
    val loc = object {
        var x = 100
        var y = 200
    }
    println(loc.x)
    //相當(dāng)于調(diào)用函數(shù)
    NetworkRequestManager.register()

    //半生對(duì)象的方法,與類關(guān)聯(lián)性強(qiáng)
    IDCard.create()
}

//對(duì)象聲明,不能用在函數(shù)中
    //一般用于對(duì)其他類使用上的包裝
object NetworkRequestManager{
    fun register(){
        println("連接網(wǎng)絡(luò)注冊(cè)中...")
    }
}

//半生對(duì)象:一般用于創(chuàng)建一個(gè)類的實(shí)例"工廠"方法
//Java中的 靜態(tài)成員
class IDCard{
    companion object {
        fun create() = IDCard()
    }
}

white
100
連接網(wǎng)絡(luò)注冊(cè)中...

6.半生對(duì)象與靜態(tài)成員

  • 每個(gè)類可以對(duì)應(yīng)一個(gè)伴生對(duì)象
  • 伴生對(duì)象的成員全局獨(dú)一份
  • 伴生對(duì)象的成員類似Java的靜態(tài)成員
  • 靜態(tài)成員考慮用包級(jí)函數(shù)、變量替代
  • JvmField和JvmStatic的使用
fun main(args: Array<String>) {
    val a = minOf(args[0].toInt(), args[1].toInt())

    val latitude = Latitude.ofDouble(3.0)

    val latitude2 = Latitude.ofLatitude(latitude)

    println(Latitude.TAG)
}

class Latitude private constructor(val value: Double) {
    companion object {
        @JvmStatic
        fun ofDouble(double: Double): Latitude {
            return Latitude(double)
        }

        fun ofLatitude(latitude: Latitude): Latitude {
            return Latitude(latitude.value)
        }
        @JvmField
        val TAG:String = "Latitude"
    }
}
Latitude

JvmStatic JvmField 用于Java類調(diào)用

public class StaticJava {
    public static void main(String[] args){
        Latitude latitude = Latitude.ofDouble(4);
        System.out.println("Java:"+Latitude.TAG);
    }
}
Java:Latitude

6.方法重載Overloads 和默認(rèn)參數(shù)

方法重載Overloads
  • 名稱相同、參數(shù)不同的方法
  • Jvm函數(shù)簽名的概念:函數(shù)名、參數(shù)列表
  • 跟返回值沒(méi)有關(guān)系
默認(rèn)參數(shù)
  • 為函數(shù)參數(shù)設(shè)定一個(gè)默認(rèn)值
  • 可以為任意位置的參數(shù)設(shè)置默認(rèn)值
  • 函數(shù)調(diào)用產(chǎn)生混淆時(shí)用具名參數(shù)
兩者關(guān)系
  • 避免定義關(guān)系不大的重載
  • 方法重載最好能轉(zhuǎn)化為默認(rèn)參數(shù)
  • 不好的設(shè)計(jì):
- List.remove(int)
- List.remove(Object)
//方法重載和函數(shù)名有和參數(shù)列表有關(guān)系,和函數(shù)返回值沒(méi)關(guān)系
class Overloads {
    //    fun a(): Int {
//        return 0
//    }
    @JvmOverloads //默認(rèn)參數(shù) 是給java調(diào)用的
    fun a(int: Int = 0): Int {
        return int
    }

}

fun main(args: Array<String>) {
    val overloads = Overloads()
    overloads.a()

    val integerList = ArrayList<Int>()
    integerList.add(555)
    integerList.add(2)
    integerList.add(3)
    integerList.add(4)
    integerList.add(9)
    integerList.add(45)

    println(integerList.toString())
    integerList.removeAt(1)
    integerList.remove(9)
    println(integerList.toString())
}
[555, 2, 3, 4, 9, 45]
[555, 3, 4, 45]

7.擴(kuò)展成員

  • Java調(diào)用擴(kuò)展成員類似調(diào)用靜態(tài)方法
  • 為現(xiàn)有類添加方法、屬性
- fun X.y():Z{...}
- val X.m 主義擴(kuò)展屬性不能初始化,類似接口屬性
fun main(args: Array<String>) {

    println("abc" * 16)
    "abc".b = 5
    println("abc".b)
}

operator fun String.times(int: Int): String {

    val stringBuilder = StringBuilder()

    for (i in 0 until int) {
        stringBuilder.append(this)
    }
    return stringBuilder.toString()
}

val String.a: String
    get() = "abc"

var String.b: Int
    set(value) {
    }
    get() = 5
abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
5

8.屬性代理

  • 定義方法:
- val/var <property name>:<Type> by
  <expression>
  • 代理者需要實(shí)現(xiàn)相應(yīng)的setValue/getValue方法:
  • lazy原理剖析

9.數(shù)據(jù)類

  • 再見(jiàn),JavaBean
  • 默認(rèn)實(shí)現(xiàn)的copy,toString等方法
  • componentN方法
  • allOpen和noArg插件 在編譯器 把final關(guān)鍵字去掉
import com.haocai.kotlindemo.annotations.Poko

@Poko
data class Country(val id: Int, val name: String)

class ComponentX {
    operator fun component1(): String {
        return "您還,我是"
    }

    operator fun component2(): Int {
        return 1
    }

    operator fun component3(): Int {
        return 1
    }

    operator fun component4(): Int {
        return 0
    }
}

fun main(args: Array<String>) {
    val china = Country(0, "中國(guó)")
    println(china)
    println(china.component1())
    println(china.component2())

    val (id, name) = china
    println(id)
    println(name)

//    for ((index, value) in args.withIndex()) {
//        println(index)
//        println(value)
//    }

    val componentX = ComponentX()
    val (a, b, c, d) = componentX
    println("$a $b $c $d")
}

10.內(nèi)部類

  • 定義在類內(nèi)部的類
  • 與類成員有相似的訪問(wèn)控制
  • 默認(rèn)是靜態(tài)內(nèi)部類,非靜態(tài)用inner關(guān)鍵字
  • this@Outter,this@Inner的用法
  • 沒(méi)有定義名字的內(nèi)部類
  • 類名編譯時(shí)生成,類似Outter$1.class
  • 可繼承父類、實(shí)現(xiàn)多個(gè)接口,與Java注意區(qū)別
Kotlin寫(xiě)法:
open class Outter {
    val a: Int = 0

    inner class Inner {
        val a: Int = 5
        fun hello() {
            println(this@Outter.a)
        }
    }
}

interface OnClickListener {
    fun onClick()
}

class View {
    var onClickListener: OnClickListener? = null
}

fun main(args: Array<String>) {
    val inner = Outter().Inner()
    inner.hello()

    val view = View()
    //匿名內(nèi)部類 即可以實(shí)現(xiàn)接口,同時(shí)繼承外部類(如,Outter())
    view.onClickListener = object : Outter(),OnClickListener{
        override fun onClick() {

        }
    }
}
0
Java類似寫(xiě)法:
public class InnerClassJava {
    private int a;

    public static void main(String... args) {
        InnerClassJava innerClassJava = new InnerClassJava();
        Inner inner = innerClassJava.new Inner();
        //Inner inner = new Inner(); 報(bào)錯(cuò) 除非Inner 是靜態(tài)
        inner.hello();

        View view = new View();
        view.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick() {

            }
        });
    }

    public class Inner {
        public void hello() {
            System.out.println(InnerClassJava.this.a); //非靜態(tài)內(nèi)部類可以持有外部類的狀態(tài)
        }
    }
}

0

11.枚舉

  • 實(shí)例可數(shù)的參數(shù),注意枚舉也是類
  • 可以修改構(gòu)造,添加成員
  • 可以提升代碼的表現(xiàn)力,也有一定的性能開(kāi)銷
enum class LogLevel(val id: Int) {
    VERBOSE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4), ASSERT(5);

    fun getTag(): String {
        return "$id,$name"
    }

    override fun toString(): String {
        return "$name,$ordinal"
    }
}

class LogLevel2 protected constructor() {
    companion object {
        val VERBOSE = LogLevel2()
        val DEBUG = LogLevel2
        val INFO = LogLevel2
        val WARN = LogLevel2
        val ERROR = LogLevel2
        val ASSERT = LogLevel2

    }
}

fun main(args: Array<String>) {
    println(LogLevel.INFO.getTag())
    println(LogLevel.DEBUG.ordinal)
    LogLevel.values().map(::println)
}
2,INFO
1
VERBOSE,0
DEBUG,1
INFO,2
WARN,3
ERROR,4
ASSERT,5

12.密封類

  • 子類可數(shù)(從v1.1開(kāi)始,只需要與密封類在同一個(gè)文件中)
  • 枚舉是實(shí)例可數(shù)
sealed class PlayerCmd{
    class Play(val url:String ,val position:Long = 0):PlayerCmd()

    class Seek(val position:Long ):PlayerCmd()

    object Pause:PlayerCmd()

    object Resume:PlayerCmd()

    object Stop:PlayerCmd()
}

enum class PlayerState{
    IDLE,PAUSE,PLAYING
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容