Kotlin学习:类、对象、接口

839 阅读5分钟

Kotlin Class, object, and interfaces

Kotlin中的接口:interface关键字 不同于java方法的implement和extends,kotlin使用的是冒号: 来完成这个方法。 也不同与java的注释override,我们使用关键词override来强制实现。

接口默认实现:

interface Clickable{
    fun click() // 方法声明
    fun showOff() = println("i am clickable") // 接口默认实现
}

对于接口默认实现的方法:

  1. 我们可以直接使用
  2. 我们也可以重写这个方法
interface Focusable{
    fun setFocus(b: boolean) = println("I ${if(b) "got" else "Losr"} focus")
    
    fun showOff() = println("i'm foucusable! ")
}

如果一个类实现了多个接口,而多个接口却有相同的方法,我们需要具体指定实现哪一个方法

class Button: Clickable, Focusable{
    override fun click() = println("I was clicked")
    
    override fun showOff(){
        super<Clickable>.showOff()
        super<Focusable>.showOff()
    }
}

final by default

kotlin中的类默认都是final ,在Effective java中提到了一点:『design and document for inheritance or else prohibit it』

// 这个类可以被其他类继承
open class RichButton: Clickable {
    fun disable(){} // fun 默认是final 表示这个方法可以被复写
    open fun animate(){} // open fun 表示你可以复写这个方法
    override fun click(){} // 这个方法复写一个open fun 它同样也是open fun 可以被人复写
    final override fun click1(){} // 但是被final修饰了 所以不可以被其他复写
}

abstract

和java一样 abstract表示的是这个类不可以被实例化,一个抽象类可以包含抽象对象和抽象方法,抽象类中的所有的方法都是open

abstract class Animated{
    abstract fun animate()
    
    open fun stopAnimating(){}
    
    fun animateTwice(){}
}
modifier corresponding member Comments
final can't be overridden Used by default
open Can be overridden Should be specified
Abstract Must be overridden Can be used only in abstract class
override overrides a member in superclass Overrideen member is open by default if not marked final

pubic by default

kotlin只有三个标识修饰关键字:public protected private。 去掉了java中的package-private,在Kotlin中packages只是在namespace中来组织代码而已。

modifier class member Top-level declaration
public visible everywhere Visible everywhere
Protected visible in subclassed
private visible in a class visible in a file

Inner And nested class: nested by default

Kotlin中的嵌套类不能访问外部类的对象实例,

interface State : Serializable
interface View{
 	fun getCurrentState() : State
    fun restoreState(state: State){}
}

public class Button implements View{
    public State getCurrentState(){
        return new ButtonState();
    }
    
 	public void restoreState(State state){}
    public class ButtonState implement State{}
}

在很多常见的场景,我们都需要创建一个内部类来存储外部类的状态,在上面的代码中当我们调用getCurrentState()来序列化我们会报错,因为这里面有一个问题便是 内部类ButtonState实现了State这个可以序列化的同时其实它还隐藏的持有了外部类的引用 因为Button没有实现序列化的接口导致报错。

class A declared whthin another class B In Java In Kotlin
Nested class State class A class A
Inner class class A Inner class A

sealed 关键字

我们都知道enum枚举 表示有限的集合,但是enum对应的其实是基本数据类型。在kotlin中类的表达其实是sealed,两者高度相似。

类中的constructor

kotlin中的构造函数分为两种,因为kotlin中允许可以默认参数 所以kotlin的写法中不太需要过载方法 一般只需要设置一些默认参数就可以

// kotlin中的原创写法 简洁不少 去掉了constructor 同时不用申明变量
class User(val nickName: String)

// 想java一种使用关键词constructor init super this
class User constructor(_nickname: String){
    val nickname:String
    //此处初始化可以多次使用 按照声明的顺序按顺序执行
    init{
        nickname = _nickname
    }
    
    init{
        nick
    }
}

class MyButton : View{
    constructor(ctx: Context):super(ctx){
        
    }
}

interface中的变量

interface User{
    val nickName: String
}

接口中的声明的变量如何去初始化

class PrivateUser(override val nickname:String) :User

class SubscribeingUser(val email: String) : User{
    override val nickname;String
    	get() = email.substringbefore('@')   
}

class FaceBookUser(val accountId: Int) : User{
	override val nickname = getFacebookName(accountId)
}

类的装饰模式 by 关键字

class DelegatingCollection<T>(innerList: Collection<T> = ArrayList<T>()):Collection<T> by innerList

类的单例模式 object 关键字

  1. 类的单例模式
object Payroll{
    val allEmployees = arrayListOf<Person>()
    
    fun calculateSalary(){
        for(person in allEmployees){
            
        }
    }
}

object 中的对象没有所谓的构造器,对象的生成在定义的时候就会立即生成,而不是通过偶在函数来生成的

object的对象的调用之间使用 . 即可,这一点和javascript中的字面对象有点像

Payroll.allEmployees.add(Person(...))
Payroll.calculateSalary()

Object 对象也可以被类继承和接口实现。

  1. Static 静态方法和对象

    直接创建一个工厂模式 也就是所谓的静态方法

    class User(val nickname: String){
        companion object{
            fun newBeginingUser(email:String) = User("")
            fun newFacebookUser(accountId: Int) = User(account)
        }
    }
    

    使用方法:

    val subscribeingUser = User.newBeginingUser("bob@email.com")
    val facebookUser = User.newFacebookUser(3)
    
  2. 匿名内部类

    Object可以充当一个匿名内部类来使用

    window.addMouselistener(object: MouseAdapter(){
        ...
    })
    

Summary

  • Interface 在Kotlin中和Java类似 除了可以拥有默认的方法实现和属性
  • 所有的声明默认都是 final public
  • 想让声明不是final 需要使用关键open
  • Nested class 默认是不外部类有引用关系, 可以使用关键字 inner 来内部类与外部类有引用关系
  • 关键字 sealed 可以将有限的子类包含在父类中(在when 中可以去掉else 因为包含了所有的可能性)
  • 除了 第一构造函数外,我们还有 init constructor 来灵活初始化对象
  • field 可以提供便捷的对象的set() get()方法的使用
  • data 也就是所谓的Javabean 关键字可以提供 equals hashCode toString copy 等便捷的方法
  • by 关键字可以提供类似代理模式
  • object 关键字 可以提供单例模式
  • companion object 替代了java所有的静态方法和属性定义
  • object 关键字可以替代java中的匿名内部类