类 对象 接口
类继承结构
- kotlin接口
声明一个接口
interface Clickable{
fun click()
}
实现这个接口
class Button :Clickable{
override fun click() = print("I'm clicked") //这里的override是强制要求的不能省略
}
拥有默认实现方法的接口
interface Clickable{
fun click()
fun showOff() = println("I'm showOff")//默认实现方法
}
注意:如果多个继承出现了同名方法,如果不手动实现会报错,或者可以指定调用函数的方法如下:
interface Clickable{
fun click()
fun showOff() = println("I'm Clickable showOff")//默认实现方法
}
interface Focusable{
fun showOff() = println("I'm Focusable showOff")
}
class Button :Clickable,Focusable{
override fun showOff() {
//调用focusable.showOff()方法,前提是showOff()方法已经实现,要不会报错
//在Java中使用的是Focusable.super.showOff();
super<Focusable>.showOff()
}
override fun click() = println("I'm clicked")
}
注意:kotlin在接口实现的方法,经过编译后,会生成一个接口和一个静态类,这个类用于实现接口
在kotlin中,所有方法修饰
重写在基类中定义的成员
open final 和abstract修饰符默认为final
SO: 如果你允许创建这个类的子类,需要使用open修饰
open class RightButton : Clickable { //声明一个可以被子类继承的类
override fun click() {} // click的父类为 open,子类默认为open
fun disable(){} //默认为final 子类不能继承
open fun animate(){} //子类可以继承
}
Open类和智能转换
- 智能转换只能是作用在,类型检查后没有改变过的变量上作用,也就是说只能在val上使用,并且是没有自定义访问器的类属性上使用。前提是,这个类必须是final的。kotlin默认为final修饰,在很多地方使用智能转换。很大程度上提高了代码表现力
- abstract默认为open interface接口中只能是默认为open,且不能使用final修饰
可见修饰符 public
-
kotlin中,如果省略修饰符,默认是可见的//在Java中默认是私有的
-
internal 修饰符-》只在模块内可见 修正了Java中,封装容易被打破的弱点

-
嵌套类和内部类在Java和kotlin中的关系
| 声明 | Java | kotlin |
|---|---|---|
| 嵌套类(不存储外部类应用) | static class A |
class A |
| 内部类(保存外部类引用) | class A |
inner class A |
- 密封类 sealed 如果在when处理所有用sealed修饰的类,就不需要提供默认分支。
sealed class Expr {
class Num(val value: Int) : Expr()
class Sum(val leftValue: Int, val rightValue: Int) : Expr()
}
//调用
fun evel(expr: Expr) {
when (expr) {
is Expr.Num -> println("num is ${expr.value}")
}
}
密封类不能在类的外部拥有子类 sealed默认就有open属性
声明一个带非默认构造方法类或属性的类
关键字constructor,用于表示一个主构造方法
class User(val nikeName: String)
//显式构造方法
//初始化
class User(_nikeName: String){
val nikeName = _nikeName //作者推荐使用下划线表示参数变量
}
//或者
class User(_nikeName: String){
val nikeName: String
init{//初始化代码块
nikeName = _nikeName //作者推荐使用下划线表示参数变量
}
}
//私有化构造方法
class User(var name: String, var age: Int, var address: String){
private class constructor(name: String)
}
//通常会写成这样
class View private constructor(context: Context) { //私有构造方法
}
//委托构造方法
open class View {
constructor(context: Context) : this(context, attributes = "attr")//委托给这个类另外一个构造方法
constructor(context: Context, attributes: Attributes)
}
实现接口中声明的属性
interface User{
val name: String
}
class PrivateUser():User{
override val name: String
get() = "Bob" //这里可以直接写函数,每次调用都会从get获取
}
//上面可以简写成
class PrivateUser(override val name: String) :User //在默认构造函数赋值,这里是只在初始化,赋值一次
通过getter 和setter访问支持的属性
class User(private val name: String) {
var address: String = "unspecified"
set(value) {
println("""
Address is change for $name
$field -> $value
""".trimIndent())
field = value
}
}
数据类和委托类 by关键字
data class Client(val name: String,val postCode: Int)
//这里会自动生成方法
//toString()
//equls()
//hashCode()
注意:equls()和hashCode是根据默认构造方法参数自动生成的,如果默认构造方法没有参数,则不会生成任何代码
数据类的不可变性 copy
创建副本是修改类的最好方法。
val client = Client("Bob",510000)
val clientCopy = client.copy()
类委托 by
- 通常我们需要给一个类添加一些行为,常用方法是 装饰者模式
本质就是创建一个类实现原始类所有的接口,并将原来的类作为一个字段保存,与原始类拥有同样的方法不需要修改,只需要转发就可以了。
缺点:
需要写很多的模版代码(在Java中)
kotlin实现:
class countSet<T>(private val innerSet: MutableCollection<T> = HashSet()) : MutableCollection<T> by innerSet{//
var objectAdd = 0
override fun add(element: T): Boolean {
objectAdd ++
return innerSet.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
objectAdd +=elements.size
return innerSet.addAll(elements)
}
}
object 关键字 核心思想:定义一个类,并创建这个类对象
主要用在以下场景:
- 对象生命 ->声明一个单例
- 伴生对象//可以访问类中所有属性,包括隐藏的属性
- 对象表达式,代替Java中的匿名类
class A{
companion object {
fun bar(){
println("companion form A")
}
}
}
伴生对象是理想的工厂模式
class Employee{
private val nickName:String
constructor(email:String){
nickName = email.substringBefore("@")
}
constructor(faceBooxId:Int){
nickName = getFaceBookName(faceBooxId)
}
}
//使用伴生对象优化可以这样写
class Employee private constructor(nickName: String) {
companion object { //这里的伴生对象可以是匿名,也可以指定名字
fun newSubcribingEmployee(email: String) = Employee(email.substringBefore("@"))
fun newFaceBookUser(account: Int) = Employee(getFaceBookId(account))
}
}
工程模式可以根据用途命名,非常有用,命名清晰避免创建新实例。
class Person(val name:String){
companion object Loader{ //一般是省略不写
fun formJson(name: String):Person{
return Person(name)
}
}
}
//调用
println(Person.Loader.formJson("哈哈哈")) //Loader可以省略不写,因为每一个class只有一个伴生对象
匿名对象
eg:使用匿名对象实现事件监听
windows.addMouseListener{
object :MouseAdapter(){
override fun mouseClicked(e: MouseEvent?) {
super.mouseClicked(e)
}
override fun mouseDragged(e: MouseEvent?) {
super.mouseDragged(e)
}
}
}
kotlin匿名内不能,访问外部类不需要外部对象final声明,而且可以改变这个外部类的值
fun countClick(window: Window) {
var clickCount = 0
window.addMouseListener(object : MouseAdapter() { //这里的只需要写需要重新的方法
override fun mouseClicked(e: MouseEvent?) {
super.mouseClicked(e)
clickCount++
}
})
}
kotlin的匿名内部类不需要重新所有的抽象方法,只需要重新自己需要重写部分即可
end