美文网首页
kotlin从入门到看开 ₅

kotlin从入门到看开 ₅

作者: 東方月初 | 来源:发表于2018-10-30 12:00 被阅读9次

layout: post
title: "kotlin-面向对象"
subtitle: "前途和未卜都未必能够回报我的任性"


面向对象

在Java中有继承 封装 和 多态 那么在Kotlin中自然也是有的.这里不再累述

//继承
class MyDrived() : MyBase() {  
    override fun method1() {}  
}  

类及其成员的可见性

Kotlin

  • public : 均可见

  • private : 只用类内部可见

  • protected : 子类可见

  • internal : 模块内可见(model内可见)

object

object这是个什么东西呢?

  1. 只有一个实例的类
  2. 不能自定义构造方法
  3. 可以实现接口,继承父类
  4. 本质上就是单利模式的最基本实现
class Driver

interface OnExternalDriverMountListener {
    fun onMount(driver: Driver)

    fun onUnmount(driver: Driver)
}

abstract class Player

object MusicPlayer : Player(), OnExternalDriverMountListener {
    override fun onMount(driver: Driver) {}

    override fun onUnmount(driver: Driver) {}

    val state: Int = 0

    fun play(url: String) {}

    fun stop() {}
}

伴生对象

  • 伴生对象与Java中的静态方法类似
  • 每个类可以对应一个伴生对象
  • 伴生对象的成员全局只有一份

companion object

Kotlin中使用方式

  1. 可以通过 类名.函数名 调用函数
  2. 那么变量 类名.变量名 调用变量

Java中若想调用

  1. 在函数上加 @JvmStatic 注解
  2. 在变量上加 @JvmField 注解 既可以正常调用

伴生对象的写法如下:

fun main(args: Array<String>) {
    println(Girl.sing("来相思树下"))
    println(Girl.TAG)
}

class Girl private constructor() {
    companion object {
        @JvmStatic
        fun sing(song: String): String {

            return song
        }

        @JvmStatic
        fun dance(dance: String): String {
            return dance
        }

        @JvmField
        val TAG: String = "涂山苏苏"
    }
}

幕后字段

kotlin没有显示字段,所有为字段赋值的操作都会调用set方法,对于一些必须要直接赋值的操作提供了幕后字段.

field

        var i = 8
        set(value)  {
            println(value)
            field=value
        }

扩展成员

可以对Java已有的类进行扩展成员

比如我想对String类添加一个方法 对传入字符串打印N次

  1. 操作符扩展方法 字符串*3
  2. 普通方法名扩展方法 字符串.times(3)
 fun main(args: Array<String>) {
    println("lalala" * 3)
    println("lalala".times(3))

}
 operator fun String.times(time: Int): String {
            val stringBuilder = StringBuilder()
            for (i in 0 until time) {
                stringBuilder.append(this + "\n")
            }
            return stringBuilder.toString()
        }

属性代理

使用方法:
val/var <属性名>:<Type> by <代理对象>

val hello2 by X()//若是可推导出类型可不写

自定义代理时要实现相应的setValue/getValue方法

class Delegates{
    val hello by lazy {
        "HelloWorld"
    }

    val hello2 by X()

    var hello3 by X()
}

class X{
    private var value: String? = null

    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("getValue: $thisRef -> ${property.name}")
        return value?: ""
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String){
        println("setValue, $thisRef -> ${property.name} = $value")
        this.value = value
    }
}

fun main(args: Array<String>) {
    val delegates = Delegates()
    println(delegates.hello)
    println(delegates.hello2)
    println(delegates.hello3)
    delegates.hello3 = "value of hello3"
    println(delegates.hello3)
}

数据类

数据类用data关键字标记

data

data class User(val name: String, val age: Int)

数据类须满足以下要求:

  • 主构造函数需要至少有一个参数 ;
  • 主构造函数的所有参数需要标记为 val 或 var ;
  • 数据类不能是抽象\开放\密封或者内部的;
  • 在1.1之前数据类只能实现接口.自 1.1 起,数据类可以扩展其他类(示例请参见密封类).

在 JVM 中,如果生成的类需要含有一个无参的构造函数,则所有的属性必须指定默认值.

data class User(val name: String = "", val age: Int = 0)

补充:

data class 是被final修饰的不可以被继承,而且没有无参构造,这就导致它无法作为javabean使用.官方出了两个插件来解决这个问题.

    1. Projec gradle添加依赖
 dependencies {
        classpath"org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
    }
    1. 创建自己的annotation
package com.littonishir.github.annotation
annotation class Ishir
    1. Module gradle应用插件
apply plugin: 'kotlin-noarg'
apply plugin: 'kotlin-allopen'

noArg{
    annotation("com.littonishir.github.annotation.Ishir")
}

allOpen{
    annotation("com.littonishir.github.annotation.Ishir")
}

    1. 使用自己定义的annotation
package com.littonishir.github

import com.littonishir.github.annotation.Ishir

@Ishir
data class Games(val name: String, val version: String)

我们反编译这个data class Games 来看看真相吧

package com.littonishir.github;

import com.littonishir.github.annotation.Ishir;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Ishir
@Metadata(
   mv = {1, 1, 10},
   bv = {1, 0, 2},
   k = 1
)
//final修饰符已经没有了
public class Games {
   @NotNull
   private final String name;
   @NotNull
   private final String version;

   @NotNull
   public String getName() {
      return this.name;
   }

   @NotNull
   public String getVersion() {
      return this.version;
   }

   public Games(@NotNull String name, @NotNull String version) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      Intrinsics.checkParameterIsNotNull(version, "version");
      super();
      this.name = name;
      this.version = version;
   }

   @NotNull
   public final String component1() {
      return this.getName();
   }

   @NotNull
   public final String component2() {
      return this.getVersion();
   }

   @NotNull
   public final Games copy(@NotNull String name, @NotNull String version) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      Intrinsics.checkParameterIsNotNull(version, "version");
      return new Games(name, version);
   }

   // $FF: synthetic method
   // $FF: bridge method
   @NotNull
   public static Games copy$default(Games var0, String var1, String var2, int var3, Object var4) {
      if (var4 != null) {
         throw new UnsupportedOperationException("Super calls with default arguments not supported in this target, function: copy");
      } else {
         if ((var3 & 1) != 0) {
            var1 = var0.getName();
         }

         if ((var3 & 2) != 0) {
            var2 = var0.getVersion();
         }

         return var0.copy(var1, var2);
      }
   }

   public String toString() {
      return "Games(name=" + this.getName() + ", version=" + this.getVersion() + ")";
   }

   public int hashCode() {
      String var10000 = this.getName();
      int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
      String var10001 = this.getVersion();
      return var1 + (var10001 != null ? var10001.hashCode() : 0);
   }

   public boolean equals(Object var1) {
      if (this != var1) {
         if (var1 instanceof Games) {
            Games var2 = (Games)var1;
            if (Intrinsics.areEqual(this.getName(), var2.getName()) && Intrinsics.areEqual(this.getVersion(), var2.getVersion())) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
//无参构造诞生
   public Games() {
   }
}

内部类

  • 定义在类内部的类
  • 默认是静态内部类,非静态用inner 关键字标记

inner

open class Outter{
    val a: Int = 0

    inner class Inner{
        val a: Int = 5
        fun hello(){
            /**
             * 静态内部类不持有外部类的引用,不能访问外部类的成员
             * 非静态内部类持有外部类的引用,可以访问外部类的成员
             */
            println(a)
            //完整的写法
            println(this@Outter.a)
        }
    }
}

匿名内部类

  • 没有定义名字的内部类
  • 类名编译时生成,类似于Outter$1.class
  • 可以继承父类实现多个接口,Java不可以继承父类在这里
    //匿名内部类的写法
    val textView = TextView(this)
    textView.setOnClickListener {object : View.OnClickListener {
                    override fun onClick(view: View?) {
                        textView.text = "hi"
                    }
                }
            }
    //lambda的写法
    textview.setOnClickListener { textview.text = "hi" }

枚举

  • 实例可数的类,注意枚举也是类
  • 可以修改构造,添加成员
  • 可以提升代码的表现力,也有一定的性能开销

enum

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"
            }
        }

        fun main(args: Array<String>) {
            println(LogLevel.DEBUG.ordinal)
            LogLevel.values().map(::println)
            println(LogLevel.valueOf("ERROR"))
        }

密封类

  • 子类可数
  • 1.1之前子类必须定义在密封类的内部
  • 1.1之后子类只需要与密封类在同一个文件中

sealed

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
}

相关文章

网友评论

      本文标题:kotlin从入门到看开 ₅

      本文链接:https://www.haomeiwen.com/subject/wbfgtqtx.html