04kotlin数据类与对象声明委托

数据类于对象声明

1.数据类

/**
 *  编译器自动从主构造函数中声明的所有属性导出以下成员:
 *  equals()/hashCode() 对;
 *  toString() 格式是 "User(name=John, age=42)";
 *  componentN() 函数 按声明顺序对应于所有属性;
 *  copy() 函数(见下文)。
 */

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

//如果在数据类体中有显式实现 equals()、 hashCode() 或者 toString(),或者这些函数在父类中有 final 实现,那么不会生成这些函数,而会使用现有函数;

2.数据类默认带有的函数

equals/hashcode/toString/componentN/copy

    val jack = User(name = "Jack", age = 1)
    val olderJack = jack.copy(age = 2) // 复制一个对象
    var v2 = jack == olderJack

kotlin可以将对象进行解析

package day3class

fun main(args: Array<String>) {
    val jane = User("Jane", 35)
    val (name, age) = jane //将jane对象解析
    //等价于java中
//    String name = jane.component1();
//    int age = jane.component2();
    println("$name, $age years of age") // 输出 "Jane, 35 years of age"
}

3.sealed密封类

无实例化无抽象成员的类 sealed,只能在本件中使用,子类可以在任何地方使用。

package day3class

/**
 * 密封类用来表示受限的类继承结构:当一个值为有限几种的类型、而不能有任何其他类型时。在某种意义上,
 * 他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。
 * 要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明。
 * 简单来说:
 * 1.类似枚举
 * 2.子类必须在密封类本文件中
 */

/**
 * sealed类使用注意点
 * 1.一个密封类是自身抽象的,它不能直接实例化并可以有抽象(abstract)成员。
 * 2.密封类不允许有非-private 构造函数(其构造函数默认为 private)。
 * 3.请注意,扩展密封类子类的类(间接继承者)可以放在任何位置,而无需在同一个文件中。
 */
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

fun eval(expr: Expr): Double = when (expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
    // 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}
fun main(args: Array<String>) {
    var consts = Const(2.0)
    println(eval(consts))
}

4.嵌套类

class Outer2 {
    private val bar: Int = 1

    inner class Inner {
        fun foo() = bar
    }
}

5.枚举类

enum class Direction {
    NORTH, SOUTH, WEST, EAST
}

/**
 * 因为每一个枚举都是枚举类的实例,所以他们可以是这样初始化过的:
 */
enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}
/**
 * 枚举常量还可以声明其带有相应方法以及覆盖了基类方法的匿名类
 * 枚举条目不能包含内部类以外的嵌套类型
 */
enum class ProtocolState {
    WAITING {
        override fun signal() = TALKING
    },

    TALKING {
        override fun signal() = WAITING
    };

    abstract fun signal(): ProtocolState
}

6.内联类

/**
 * 内联类仅在 Kotlin 1.3 之后版本可用,
 *
 * 然而,内联类的成员也有一些限制:

内联类不能含有 init 代码块
内联类不能含有幕后字段
因此,内联类只能含有简单的计算属性(不能含有延迟初始化/委托属性)
 */
inline class Name(val s: String) {
    val length: Int
        get() = s.length

    fun greet() {
        println("Hello, $s")
    }
}

7.泛型

1.泛型类
package day3class

class Box<T>(t: T) {
    var value = t

    fun printBox(): T {
        return value
    }

    fun setBoxValue(v: T) {
        value = v
    }
}

fun main(args: Array<String>) {
    val box: Box<Int> = Box<Int>(1) // java中写法
    //由于kotlin中有智能类型,可以简化
    val box2 = Box(1)
}
2.泛型函数
package day3class
fun <T> singletonList(item: T): List<T> {
    return listOf(item)
}

fun <T> T.basicToString(): String {  // 扩展函数
    return "a"
}

fun main(args: Array<String>) {
    val l = singletonList<Int>(1)
}

/**
 * 等价于java中 extends
 */

8.Out和In协变与逆变

1.Out协变
out协变,读取的对象为生产者,代表的意思
2.in 逆变

只可以写入,不能读取

9.单例对象声明

1.第一种方式

懒汉模式

object DataProviderManager {
    var b: Int = 3
    fun method1() {
    }

    @JvmStatic
    fun method2() {
    }
}
2.静态内部类
class Singleton private constructor() {
    init {
        println("This ($this) is a singleton")
    }

    private object Holder {
        val INSTANCE = Singleton()
    }

    companion object {
        val instance: Singleton by lazy { Holder.INSTANCE }
    }

    var b: String? = null
}

等价于java

package com.company.koltin2;

public class SingleTonClass {
    public static class SingleTon {
        static final SingleTonClass INSTANCE = new SingleTonClass();
    }

    public static SingleTonClass getInstance() {
        return SingleTon.INSTANCE;
    }
}
3.双锁校验
class Singleton2 private constructor(str: String) {
    var str2: String = str;

    init {
        println("str is $str")
        println("string is $str2")
    }

    companion object {
        @Volatile
        var instance: Singleton2? = null

        fun getInstance(c: String): Singleton2 {
            if (instance == null) {
                synchronized(Singleton::class) {
                    if (instance == null) {
                        instance = Singleton2(c)
                    }
                }
            }
//            instance ?: synchronized(Singleton::class) {
//                instance ?: Singleton2(c)
//            }
            return instance!!
        }

        @Synchronized
        fun method() {

        }
        
        /**
         * 双锁校验,等同于下面方式
         */
        fun getInstance2(c: String) = instance ?: synchronized(Singleton::class) {
            instance ?: Singleton2(c)
        }

        fun getString() = instance
    }
}

/**
 * 双锁校验
 *
 */
class Singleton5 {
    var a = 2

    companion object {
        val instance: Singleton5 by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            Singleton5()
        }

        @JvmStatic
        fun method3() {

        }
    }

    fun addxxx() {

    }
}
4.饿汉模式
class SingletonDemo private constructor() {
    companion object {
        private var instance: SingletonDemo? = null
            get() {
                if (field == null) {
                    field = SingletonDemo()
                }
                return field
            }

        @Synchronized
        fun get2(): SingletonDemo {
            return instance!!
        }
    }
}
5.静态单例模式
/**
 * 静态单例单例模式
 */
class Singleton6 private constructor() {
    init {
        println("This ($this) is a singleton")
    }

    companion object {
        val instance: Singleton6 by lazy { Singleton6() }
    }

    var b: String? = null
}

10.半生对象

//半生对象,半生对象,就相当于java中静态内部类,
//内部成员,就相当于在java中static
class MyClass2 {
    companion object Factory {
        var a: Int = 0
        const val b: Int = 2
        fun create(): MyClass2 = MyClass2()
    }
}

11.半生对象静态final

/**
 * const只能在没有声明class的文件中,或者在半生对象中
 * const与val区别,
 * val如果在没有声明class的文件中或者半生对象中,是private static final ,由getter方法
 * 如果在类中,是private final,由getter方法
 *
 * 注意,半生对象还是由自己的对象,可以实现接口
 *
 */
interface Factory<T> {
    fun create(): T
}

/**
 * 注意,半生对象还是有自己的对象,默认Companion,可以实现接口
 */
class MyClass5 {
    companion object : Factory<MyClass5> {
        override fun create(): MyClass5 = MyClass5()
    }
}

fun main(args: Array<String>) {
    val f: MyClass5 = MyClass5.Companion.create()
}

12.函数别名

typealias MyHandler = (Int, String, Any) -> Unit

/**
 * 传参是一个T,返回一个boolean类型
 */
typealias Predicate<T> = (T) -> Boolean

13.委托

/**
 * 使用override 覆盖的实现,那么会首先实现自己的方法,而不是委托对象,属性也是如此,所以使用委托对象时,尽量不要在自身类中实现方法,避免调用错乱
 * 可以实现代理模式,简化了代理模式
 */

——————个人觉得,委托最大作用就是简化了代理模式,让自己的函数交给其他类去实现或执行。

package day3class
/**
 * 属性也是如此
 */
interface Base5 {
    val message: String
    fun print()
}
class Base5Impl(val x: Int) : Base5 {
    override val message = "Base5Impl: x = $x"
    override fun print() { println(message) }
}
class Derived4(b: Base5) : Base5 by b {
    // 在 b 的 `print` 实现中不会访问到这个属性
    override val message = "Message of Derived4"
}
fun main() {
    val b = Base5Impl(10)
    val Derived4 = Derived4(b)
    Derived4.print()
    println(Derived4.message)
}

14.lazy委托常用

lazy只有使用时,才去初始化

package day3class

/**
 * lazy会委托,第一次使用时,会创建一次,后续都只会getter,所以只能使用final常量
 * 非常常用,一定要会,延迟加载
 *
 *
 * 有以下几种模式,PUBLICATION,多线程, synchronized,同步锁
 * 默认情况下,对于 lazy 属性的求值是同步锁的(synchronized):
 * 该值只在一个线程中计算,并且所有线程会看到相同的值。如果初始化委托的同步锁不是必需的,这样多个线程可以同时执行,
 * 那么将 LazyThreadSafetyMode.PUBLICATION 作为参数传递给 lazy() 函数。
 * 而如果你确定初始化将总是发生在与属性使用位于相同的线程, 那么可以使用 LazyThreadSafetyMode.NONE 模式:它不会有任何线程安全的保证以及相关的开销。
 */
val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main() {
    println(lazyValue)
    println(lazyValue)
}

15.委托属性

package day3class

import kotlin.reflect.KProperty

/**
 * 有一些常见的属性类型,虽然我们可以在每次需要的时候手动实现它们, 但是如果能够为大家把他们只实现一次并放入一个库会更好。例如包括:
延迟属性(lazy properties): 其值只在首次访问时计算;
可观察属性(observable properties): 监听器会收到有关此属性变更的通知;
把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中。
 */

/**
语法是: val/var <属性名>: <类型> by <表达式>。在 by 后面的表达式是该 委托,
因为属性对应的 get()(与 set())会被委托给它的 getValue()
与 setValue() 方法。 属性的委托不必实现任何的接口,
但是需要提供一个 getValue() 函数(与 setValue()——对于 var 属性)。 例如:
 */
class Example2 {
    companion object {
        var p: String by Delegate()
    }
}

class Delegate {
    private var data: String? = null
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me $data!"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        this.data = if (data == null) value else throw IllegalStateException()
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}

fun main(args: Array<String>) {
//    val e = Example2()
    /**
     * 当我们从委托到一个 Delegate 实例的 p 读取时,将调用 Delegate 中的 getValue() 函数,
     */
    println(Example2.p)
    /**
     * 类似地,当我们给 p 赋值时,将调用 setValue() 函数。前两个参数相同,第三个参数保存将要被赋予的值:
     */
    Example2.p = "NEW"
    println(Example2.p)
}

作用:可以用来封装android中sharedPreference

16.可观察属性委托observable

/**
 * Delegates3.observable() 接受两个参数:初始值与修改时处理程序(handler)。
每当我们给属性赋值时会调用该处理程序(在赋值后执行)。它有三个参数:被赋值的属性、旧值与新值:
非常类似于Android MVVM架构中DataBinding使用
 */
class User3 {
    var name: String by Delegates.observable("") { prop, old, new ->
        println("$old -> $new")
    }
}
fun main() {
    val User3 = User3()
    User3.name = "first"
    User3.name = "second"
}

17.Map委托实现Json解析

package day3class
/**
 * 常见的用例是在一个映射(map)里存储属性的值。
 * 这经常出现在像解析 JSON 或者做其他“动态”事情的应用中。
 */
class User5(private val map: Map<String, Any?>) {
    val name: String by map
    val age: Int     by map
}

fun main(args: Array<String>) {
    val user = User5(mapOf(
            "name" to "John Doe",
            "age"  to 25
    ))
    println(user.name) // Prints "John Doe"
    println(user.age)  // Prints 25
}

-> $new")
}
}
fun main() {
val User3 = User3()
User3.name = “first”
User3.name = “second”
}


### 17.Map委托实现Json解析

```kotlin
package day3class
/**
 * 常见的用例是在一个映射(map)里存储属性的值。
 * 这经常出现在像解析 JSON 或者做其他“动态”事情的应用中。
 */
class User5(private val map: Map) {
    val name: String by map
    val age: Int     by map
}

fun main(args: Array) {
    val user = User5(mapOf(
            "name" to "John Doe",
            "age"  to 25
    ))
    println(user.name) // Prints "John Doe"
    println(user.age)  // Prints 25
}

你可能感兴趣的:(kotlin,kotlin)