数据类于对象声明
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("<no name>") { 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<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
}