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++ //更新变量的值
}
})
}