Kotlin 实战随手笔记。类、对象、接口
每天都要完成工作任务,但是还是要学点东西。
类
// 主构造方法
class User()
class User(val age:Int)
// 主构造方法和初始化语句块
class User constructor(_nickname: String) {
val nickname: String
init {
nickname = _nickname
}
}
// 带一个参数的主构造方法可简写为如下
class User constructor(_nickname: String) {
val nickname = _nickname
}
// 最后的简化
class User(val nickname: String) , val 意昧着相应的属性会用构造方法 的参数来初始化
Java
中类的修饰符有 publish、private、protected
,Kotlin
中也有类修饰符
open、 final 和 abstract
修饰符:默认为 final
下面是Kotlin
中各个类修饰符的相关介绍:
修饰符 | 相关成员 | 评注 |
---|---|---|
final | 不能被重写 | 类中成员默认使用 |
open | 可以被重写 | 需要明确地表明 |
abstract | 必须被重写 | 只能在抽象类中使用:抽象成员不能有实现 |
override | 重写父类或接口中的成员 | 如果没有使用 final 表明,重写的成员默认是开放的 |
Java 中的默认可见性一一包私有,而在 Kotlin 中井没有使用。 Kotlin 只把包作为 在命名空间里组织代码的一种方式使用 ,并没有将其用作可见性控制。
下面是Kotlin
中各个类修饰符的可见性:
修饰符 | 类成员 | 顶层声明 |
---|---|---|
public (默认) | 所有地方可见 | 所有地方可见 |
internal | 模块中可见 | 模块中可见 |
protected | 子类中可见 | – |
private | 类中可见 | 文件中可 |
访问可见性例子
internal open class TalkativeButton : Focusable {
private fun yell() = println("Hey!”)
protected fun whisper () = println ("Let ’ s talk !")
}
fun TalkativeButton.giveSpeech() {// 错误,Kotlin 禁止从 public 函数 giveSpeech 去引用低可见的类型 TalkativeButton (这个例子中是 internal )。
yell() // 错误,它在"TalkativeButton"中是 private 不能访问
whisper () // 错误,它在"TalkativeButton"中是"protected"的 不能访问
}
要解 决上面例子中的问题,既可以把函数改为internal
的,也可以把类改成 public
的。
注意, protected 修饰符在 Java 和 Kotlin 中不同的行为。在 Java 中,可以从 同一个包中访问一个 protected 的成员,但是 Kotlin 不允许这样做。 在 Kotlin 中 可见性规则非常简单, protected 成员只在类和它的子类中可见。 同样还要注意 的是类的扩展函数不能访问它的 private 和 protected 成员 。
接口定义
例子:
interface Clickable {
fun click ()
}
class Button : Clickable {
override fun click() = println("I was clicked")
}
>> Button() .click() I was clicked
内部类和嵌套类:默认是嵌套类
kotlin 需用 inner 修饰,内部类默认是不能访问外部类,可以通过 this@外部类 获取外部类实例
密封类,包含有限数量的类的继承结构(嵌套类)
interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
fun eval(e: Expr): Int = when (e) {
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)
else -> throw IllegalArgumentException ("Unknown expression")
}
(去除 else 判断)
sealed class Expr {
class Num(val value :工nt) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
fun eval(e: Expr): Int = when (e) {
is Expr.Num -> e.value
is Expr.Sum -> eval(e.right) + eval(e.left)
}
}
数据类和类委托
数据类自动生成通用方法的实现 : toString、 equals 和 hashCode。
例子:直接在类前面添加data
声明是数据类
data class Client(val name: String, val postalCode: Int)
类委托:使用“by”关键字
参考:https://www.runoob.com/kotlin/kotlin-delegated.html
类的委托即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。
无论什么时候 实现一个接口,你都可以使用 by 关键字将接口的实现委托到另一个对象。
// 创建接口
interface Base {
fun print()
}
// 实现此接口的被委托的类
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
// 通过关键字 by 建立委托类
class Derived(b: Base) : Base by b
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // 输出 10
}
object 关键字:将声明一个类与创建一个实例 结合起来
- 对象声明是定义单例的一种方式。
object Payroll {
val allErnployees = arrayListOf<Person>{)
fun calculateSalary() {
for (person in allErnployees) { }
}
}
Payroll.allEmployees.add(Person( ... ))
Payroll.calculateSalary()
- 伴生对象可以持有工厂方法和其他与这个类相关,但在调用时并不依赖类实 例的方法。 它们的成员可以通过类名来访问。
class A {
companion object {
fun bar() {
println ("Companion object called")
}
}
}
>> A.bar()
Companion object called
- 对象表达式用来替代 Java 的匿名内部类
val listener = object : MouseAdapter() {
override fun rnouseClicked(e: MouseEvent) { .. . }
override fun rnouseEntered(e: MouseEvent) { ... }
}
adapter.listener = listener
完!