Kotlin实战(三) 类,对象和接口

1 定义类继承结构

1.1 Kotlin中的接口
//1 定义一个简单的接口
interface Clickable1 {
    fun click()
}

//2 实现一个接口
class Button : Clickable1 {
    override fun click() = println("I was clicked")
}

//3 在接口中定义一个带方法体的方法
interface Clickable2 {
    fun click()
    fun showOff() = println("I'm clickable!")
}

//4 定义另一个实现了同样方法的接口
interface Focusable {
    fun setFocus(b: Boolean) = println("I ${if (b) "got" else "lost"} focus.")

    fun showOff() = println("I'm focusable!")
}

//5 实现两个接口的相同方法
class Button2 : Clickable2, Focusable {
    override fun click() {
        println("I was clicked")
    }


    override fun showOff() {
        //super中可以声明调用哪一个父类的方法
        super<Clickable2>.showOff()
        super<Focusable>.showOff()
    }
}

fun test1() {
    Button().click()
    Button2().showOff()
}

日志输出

I was clicked
I'm clickable!
I'm focusable!
1.2 open, final和abstract修饰符
//1 声明一个带open方法的open类
open class RichButton1 : Clickable1 {

    //此函数是final的 不能在子类中重写它
    fun disable() {}

    //此函数是open的 可以在子类中重写
    open fun animate() {}

    override fun click() {}
}

//2 禁止重写
open class RichButton2 : Clickable1 {

    //override修饰的函数不加final默认是open的
    final override fun click() {

    }
}

//3 声明一个抽象类
abstract class Animated {
    abstract fun animate()

    //非抽象函数默认不是open的
    open fun stopAnimating() {}

    fun animateTwice() {}
}
1.3 可见性修饰符:默认为public
internal open class TalkativeButton : Focusable {
    private fun yell() = println("Hey!")
    protected fun whisper() = println("Let's talk!")
}

//Error:TalkativeButton是internal的
fun TalkativeButton.giveSpeech(){
    yell()      //Error:yell在TalkativeButton中是private的
    whisper()   //Error:不能访问"whisper"它在TalkativeButton中是proteced的
}
1.4 内部类与嵌套类:默认是嵌套类
//1 声明一个包含可序列化状态的视图
interface State : Serializable

interface View {
    fun getCurrentState(): State
    fun restoreState(state: State) {}
}
	//2 用带内部类的java代码来实现View
    public class Button implements View{

        @NotNull
        @Override
        public State getCurrentState() {
            return new ButtonState();
        }

        @Override
        public void restoreState(@NotNull State state) {

        }

        //不能被序列化,隐式持有外部类的引用,外部类不能序列化
        //可将此类改为static类型
        class ButtonState implements State{

        }
    }
//2 如果要实现java中持有外部类的场景 需要加inner
class Outer{
    inner class Inner{
        //3 访问外部类需要使用this@Outer
        fun  getOuterReference():Outer = this@Outer
    }
}
1.5 密封类:定义受限的类继承结构
//1 作为接口实现的表达式
interface Expr

class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(e: Expr): Int =
//1使用when时,编译器会强制检查默认选项。
    // 如果后续添加新子类,忘记了添加一个新分支,就会选择默认选项,有可能导致潜在bug
    when (e) {
        is Num -> e.value
        is Sum -> eval(e.right) + eval(e.left)
        else ->
            throw IllegalArgumentException("Unknow expression")
    }

//2 作为密封类的表达式
sealed class Expr2 {
    // ----> 将基类标记为密封的
    class Num(val value: Int) : Expr2()

    class Sum(val left: Expr2, val right: Expr2) : Expr2()
}

//使用when表达式处理素有sealed类的子类,就不再需要提供默认分支
fun eval2(e: Expr2): Int =
    when (e) {
        is Expr2.Num -> e.value
        is Expr2.Sum -> eval2(e.right) + eval2(e.left)
    }

2 声明一个带默认构造方法或属性的类

2.1 初始化类:主构造方法和初始化语句块
//使用括号围起来的额语句块叫做主构造方法
class User1(val nickname: String)

//1 constructor init 方式
// constructor构造方法的声明 init:引入一个初始化的语句块
class User2 constructor(_nickname: String) {
    val nickname: String

    init {
        nickname = _nickname
    }
}

//2 属性初始化的另一种方式,此种方式最简洁
class User3(_nickname: String) {
    val nickname = _nickname
}

//3 构造方法参数的默认值
class User4(val nickname: String, val isSubscribed: Boolean = true) {

}

//4 创建一个类的实例,只需要直接调用构造方法,不需要new关键字
fun test2() {
    //isSubscribed参数使用默认值 true
    val alice = User4("Alice")
    println("alice.isSubscribed = ${alice.isSubscribed}")

    //按照声明顺序写明参数
    val bob = User4("Bob", false)
    println("bob.isSubscribed = ${bob.isSubscribed}")

    //显式地位某些构造方法参数标明名称
    val carol = User4("Carol", isSubscribed = false)
    println("carol.isSubscribed = ${carol.isSubscribed}")
}

//5 初始化父类
open class User5(val nickname: String)

class TwitterUser(nickname: String) : User5(nickname)

//6 默认构造方法
open class Button5

class RadioButton : Button5()

//7 构造方法私有
class Secretive private constructor()

日志输出

alice.isSubscribed = true
bob.isSubscribed = false
carol.isSubscribed = false
2.2 构造方法:用不同的方式来初始化父类
//1 从构造方法
open class View2 {
    constructor(ctx: Context)
    constructor(ctx: Context, attr: AttributeSet)
}

class MyButton2 : View2 {
    constructor(ctx: Context) : super(ctx)
//    constructor(ctx: Context) : this(ctx,MY_STYLE)  //也可以使用this来调用另一个构造方法
    constructor(ctx: Context, attr: AttributeSet) : super(ctx, attr)
}
2.3 实现在接口中声明的属性
interface User6 {
    val nickname: String
}

//实现一个接口属性
class PrivateUser(override val nickname: String) : User6

//自定义getter
class SubscribingUser(val email: String) : User6 {
    override val nickname: String
        get() = email.substringBefore('@')
}

fun getFacebookName(accountId: Int): String {
    return "ZhangSan"
}

//属性初始化
class FacebookUser(val accountId: Int) : User6 {
    override val nickname = getFacebookName(accountId)
}

fun test3() {
    println("PrivateUser(\"test@kotlinlang.org\").nickname = ${PrivateUser("test@kotlinlang.org").nickname}")
}

interface User7 {
    //第一个属性必须在子类中重写,第二个是可以被继承的
    val email: String
    val nickname: String
        get() = email.substringBefore('@')
}

日志输出

PrivateUser("test@kotlinlang.org").nickname = test@kotlinlang.org
SubscribingUser("test@kotlinlang.org").nickname = test
2.4 通过getter或setter访问支持字段
class User8(val name: String) {
    var address: String = "unspecified"
        set(value: String) {
            println(""" Address was changed for $name:"$field" -> "$value". """.trimIndent())
            field = value
        }
}

fun test4(){
    val user = User8("Alice")
    user.address = "Elsenheimerstrasse 47, 80687 Muenchen"
}

日志输出

Address was changed for Alice:"unspecified" -> "Elsenheimerstrasse 47, 80687 Muenchen". 
2.5 修改访问器的可见性
//声明一个具有private setter的属性

class LengthCounter {
    var counter: Int = 0
        private set

    fun addWord(word: String) {
        counter += word.length
    }
}

fun test5() {
    val lengthCounter = LengthCounter()
    lengthCounter.addWord("Hi!")

    //lengthCounter.counter = 5 //Error:The setter is private
    println(lengthCounter.counter)
}

3 编译器生成的方法:数据类型和类委托

3.1 通用对象方法
//1 Client类的最初声明
class Client1(val name: String, val postalCode: Int)

//2 为Client实现toString()
class Client2(val name: String, val postalCode: Int) {
    override fun toString() = "Client(name = $name, postalCode = $postalCode)"
}

fun test6() {
    val client = Client2("Alice", 324324)
    println(client)
}
//Client(name = Alice, postalCode = 324324)

//3 对象相等性:equals()
class Client3(val name: String, val postalCode: Int) {
    //"Any" 是java.lang.Object的模拟,是Kotlin中所有类的父类
    //可空类型"Any?"意味着"other"是可以为空的
    //"is"检查是java中的instanceof的模拟
    override fun equals(other: Any?): Boolean {
        if (other == null || other !is Client3) {
            return false
        }

        return name == other.name && postalCode == other.postalCode
    }
}

//4 hashCode()
class Client4(val name: String, val postalCode: Int) {
    override fun hashCode(): Int = name.hashCode() * 31 + postalCode
}

fun test7() {
    val client1 = Client2("Alice", 324324)
    val client2 = Client2("Alice", 324324)
    println("client1 == client2 is ${client1 == client2}")

    val client3 = Client3("Alice", 324324)
    val client4 = Client3("Alice", 324324)
    println("client3 == client4 is ${client3 == client4}")

    val client5 = Client4("Alice", 324324)
    val processed = hashSetOf(client5)
    println("processed.contains(client5) is ${processed.contains(client5)}")
}
client1 == client2 is false
client3 == client4 is true
processed.contains(client5) is true
3.2 数据类:自动生成通用方法的实现
//1 "data"修饰符的数据类client
data class Client6(val name: String, val postalCode: Int)

//2 数据类和不可变性:copy()方法
class Client7(val name: String, val postalCode: Int) {
    fun copy(name: String = this.name, postalCode: Int = this.postalCode) =
        Client7(name, postalCode)

    override fun toString() = "Client(name = $name, postalCode = $postalCode)"
}

fun test8() {
    val candy = Client6("Candy", 11242)
    println("candy.toString() = ${candy.toString()}")

    val bob = Client7("Bob", 12323)
    println(bob.copy(postalCode = 12323))
}

日志输出

Client(name = Bob, postalCode = 12323)
3.3 类委托:使用“by”关键字
class CountingSet<T>(val innerSet: MutableCollection<T> = HashSet<T>()) :
    MutableCollection<T> by innerSet {
    var objectsAdded = 0

    override fun add(element: T): Boolean {
        objectsAdded++
        return innerSet.add(element)
    }

    override fun addAll(elements: Collection<T>): Boolean {
        objectsAdded += elements.size
        return innerSet.addAll(elements)
    }
}

fun test9() {
    val cSet = CountingSet<Int>()
    cSet.addAll(listOf(1, 2, 3))
    println("${cSet.objectsAdded} objects were added ${cSet.size} remain")
}

日志输出

3 objects were added 3 remain

4 "object"关键字:将声明一个类与创建一个实例结合起来

4.1 对象声明:创建单例易如反掌
class Person(var name: String)

object Payroll {
    val allEmployees = arrayListOf<Person>()

    fun calculateSalary() {
        for (person in allEmployees) {
            println("person.name = ${person.name}")
        }
    }
}

//1 使用对象来实现Comparator
object CaseInsensitiveFileComparator : Comparator<File> {
    override fun compare(file1: File?, file2: File?): Int {
        return file1!!.path.compareTo(file2!!.path, ignoreCase = true)
    }
}

//2 使用嵌套类实现Comparator
data class Person1(val name: String) {
    object NameComparator : Comparator<Person1> {
        override fun compare(p1: Person1?, p2: Person1?): Int = p1!!.name.compareTo(p2!!.name)
    }
}

fun test10() {
    val value: Int = CaseInsensitiveFileComparator.compare(File("/User"), File("/user"))
    println("value = $value")

    val files = listOf(File("/Z"), File("/a"))
    val comparator = files.sortedWith(CaseInsensitiveFileComparator)
    println("comparator = $comparator")


    val persons = listOf(Person1("Bob"), Person1("Alice"))
    println(persons.sortedWith(Person1.NameComparator))

}

日志输出

value = 0
comparator = [/a, /Z]
[Person1(name=Alice), Person1(name=Bob)]
4.2 伴生对象:工厂方法和静态成员的地盘
class A {
    companion object {
        fun bar() {
            println("Companion object called")
        }
    }
}

//1 定义一个拥有多个从构造方法的类
class UserA {
    val nickname: String

    constructor(email: String) {
        nickname = email.substringBefore('@')
    }

    constructor(facebookAccountId: Int) {
        nickname = getFacebookName(facebookAccountId)
    }
}

//2 使用工厂方法来替代从构造方法
class UserB private constructor(val nickname: String) {
    companion object {
        fun newSubscribingUser(email: String) = UserB(email.substringBefore('@'))

        fun newFacebookUser(accountId: Int) = UserB(getFacebookName(accountId))
    }
}

fun test11() {
    A.bar()

    val subscribingUser = UserB.newSubscribingUser("bob@gmail.com")
    val facebookUser = UserB.newFacebookUser(4)

    println("subscribingUser.nickname = ${subscribingUser.nickname}")
    println("facebookUser.nickname = ${facebookUser.nickname}")
}

Companion object called
subscribingUser.nickname = bob
facebookUser.nickname = ZhangSan
4.3 作为普通对象使用的伴生对象
//1 声明一个命名伴生对象
class Person2(val name: String) {
    companion object Loader {
        fun fromJSON(jsonText: String): Person2 {
            return Person2("张三")
        }
    }
}

fun test12() {
    val person1 = Person2.Loader.fromJSON("{name:'Dmitry'}")
    println("person1.name = ${person1.name}")

    val person2 = Person2.fromJSON("{name:'Dmitry'}")
    println("person2.name = ${person2.name}")
}

输出日志

person1.name = 张三
person2.name = 张三
4.4 对象表达式:改变些发的匿名内部类
//1 使用匿名对象来实现事件监听器
fun addListener1(window: Window) {
    window.addMouseListener(
        //1 声明一个集成MouseAdapter的匿名对象
        object : MouseAdapter() {
            override fun mouseClicked(p0: MouseEvent?) {
                super.mouseClicked(p0)
            }

            override fun mouseEntered(p0: MouseEvent?) {
                super.mouseEntered(p0)
            }
        }
    )
}

//2 使用匿名对象来实现事件监听器
fun addListener2() {
    val listener = object : MouseAdapter() {
        override fun mouseClicked(p0: MouseEvent?) {
            super.mouseClicked(p0)
        }

        override fun mouseEntered(p0: MouseEvent?) {
            super.mouseEntered(p0)
        }
    }
}

//3 从匿名对象访问局部变量
fun countClicks(window: Window) {
    var clickCount = 0
    window.addMouseListener(object : MouseAdapter() {
        override fun mouseClicked(p0: MouseEvent?) {
            clickCount++ //更新变量的值
        }
    })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值