1关于复写调用父类方法
class SinleChild : GodClass() {
lateinit var aa: String
val bb by lazy { "00" }
override var vvar: Int = 1
override var vval: Int = 1
override fun funff() {
super.funff()
print("我是child")
}
inner class innn {
fun prin() {
funff()
super@SinleChild.funff()//调用godclass的funff方法
}
}
}
2覆盖规则
在 Kotlin 中,实现继承由下述规则规定:如果一个类从它的直接超类继承相同成员的多个实现, 它必须覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如 super<Base>
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } // 接口成员默认就是“open”的
fun b() { print("b") }
}
class C() : A(), B {
// 编译器要求覆盖 f():
override fun f() {
super<A>.f() // 调用 A.f()
super<B>.f() // 调用 B.f()
}
}
3setter&&getter
var stringRepresentation: String
get() = this.toString()
set(value) {
if (value >= 0) field = value
}
4扩展
Kotlin 同 C# 和 Gosu 类似,能够扩展一个类的新功能而无需继承该类或使用像装饰者这样的任何类型的设计模式。 这通过叫做 扩展 的特殊声明完成。Kotlin 支持 扩展函数 和 扩展属性。
接收者可为空
fun Any?.toString(): String {
if (this == null) return "null"
// 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
// 解析为 Any 类的成员函数
return toString()
}
注意:由于扩展没有实际的将成员插入类中,因此对扩展属性来说幕后字段是无效的。这就是为什么扩展属性不能有初始化器。他们的行为只能由显式提供的 getters/setters 定义。
val <T> List<T>.lastIndex: Int
get() = size - 1//正确
val <T> List<T>.lastIndex: Int = 1 // 错误:扩展属性不能有初始化器
5object
匿名对象可以用作只在本地和私有作用域中声明的类型。如果你使用匿名对象作为公有函数的返回类型或者用作公有属性的类型,那么该函数或属性的实际类型会是匿名对象声明的超类型,如果你没有声明任何超类型,就会是 Any。在匿名对象中添加的成员将无法访问
class C {
// 私有函数,所以其返回类型是匿名对象类型
private fun foo() = object {
val x: String = "x"
}
// 公有函数,所以其返回类型是 Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // 没问题
val x2 = publicFoo().x // 错误:未能解析的引用“x”
}
}
6委托
委托模式已经证明是实现继承的一个很好的替代方式, 而 Kotlin 可以零样板代码地原生支持它。
Derived
类可以通过将其所有公有成员都委托给指定对象来实现一个接口Base
:
interface Base {
val message:String
fun printMessage()
fun printMessageLine()
}
class BaseImpl(val x: Int) : Base {
override val message: String="messasge"
override fun printMessage() { print(x) }
override fun printMessageLine() { println(x) }
}
class Derived(b: Base) : Base by b {
//在 b 的 `print` 实现中不会访问到这个属性
override val message: String="de=message"
override fun printMessage() { print("abc") }
}
fun main(args: Array<String>) {
val b = BaseImpl(10)
print(Derived(b).message)//message
Derived(b).printMessage()//abc
Derived(b).printMessageLine()//10
}
7委托属性
kotlin提供标准的几种:
1延迟属性(lazy properties): 其值只在首次访问时计算;
2可观察属性(observable properties): 监听器会收到有关此属性变更的通知;
3把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中
lazy
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)//computed hello
println(lazyValue)//hello
}
observable这个在开发中可以常用
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
这个例子输出:
<no name> -> first
first -> second
map
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
println(user.name) // Prints "John Doe"
println(user.age) // Prints 25
这也适用于 var 属性,如果把只读的 Map 换成 MutableMap 的话:
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
为了涵盖这些(以及其他)情况,Kotlin 支持 委托属性:
class Example {
var p: String by Delegate()
}
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
val e = Example()
println(e.p)//Example@33a17727, thank you for delegating ‘p’ to me!
e.p = "NEW"//NEW has been assigned to ‘p’ in Example@33a17727.
this 的用法
要访问来自外部作用域的this(一个类 或者扩展函数, 或者带标签的带接收者的函数字面值)我们使用
this@label
,其中@label
是一个代指 this 来源的标签:
class A { // 隐式标签 @A
inner class B { // 隐式标签 @B
fun Int.foo() { // 隐式标签 @foo
val a = this@A // A 的 this
val b = this@B // B 的 this
val c = this // foo() 的接收者,一个 Int
val c1 = this@foo // foo() 的接收者,一个 Int
val funLit = lambda@ fun String.() {
val d = this // funLit 的接收者
}
val funLit2 = { s: String ->
// foo() 的接收者,因为它包含的 lambda 表达式
// 没有任何接收者
val d1 = this
}
}
}
}
9==,equlas,===
==
- 如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等2. 如果作用于引用类型的变量,则比较的是所指向的对象的地址
equals
- equals方法不能作用于基本数据类型的变量2. 如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
3.诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
===
- 对于基本数据类型,如果类型不同,其结果就是不等。如果同类型相比,与“==”一致,直接比较其存储的 “值”是否相等;2. 对于引用类型,与“==”一致,比较的是所指向的对象的地址
fun main(args: Array<String>) {
val a : Int = 10
val b : Long = 10
val c : Int = 20
val d : String = "abc"
val e : String = "abcd"
val f : String = d
val ooA : Operator = Operator("zhang", 10)
val ooB : Operator = Operator("li", 20)
val ooC : Operator = Operator("zhang", 10)
val ooD : Operator = ooA
// ==
println("-------- == -------- ")
println("a == c: ${a==c}")
println("ooA == ooC: ${ooA==ooC}")
println("ooA == ooD: ${ooA==ooD}")
println("d == e: ${d==e}")
println("f == d: ${f==d}")
// equals
println("-------- equals -------- ")
println("ooA.equals(ooC): ${ooA.equals(ooC)}")
println("d.equals(e): ${d.equals(e)}")
// ===
println("-------- === -------- ")
println("a === c: ${a===c}")
println("ooA === ooC: ${ooA===ooC}")
println("ooA === ooD: ${ooA===ooD}")
println("d === e: ${d===e}")
}
data class Operator(var name: String, var age: Int) {
override fun equals(other: Any?): Boolean {
if (other is Operator) {
return this.age == other.age
}
return false
}
}
a == c: false
ooA == ooC: true
ooA == ooD: true
d == e: false
f == d: true
-------- equals --------
ooA.equals(ooC): true
d.equals(e): false
-------- === --------
a === c: false
ooA === ooC: false
ooA === ooD: true
d === e: false
10构造函数
构造函数分为主构造函数和次构造函数,主构造函数一般写在类名后,次构造函数要委托给主构造函数
class ChildClass(age: Int){
private var age: Int
init {
//主构造函数里不能写代码,需要在init中
this.age=age
}
private lateinit var name: String
constructor(name: String):this(0){
this.name=name
}
private var b: Boolean=false
constructor(name: String, b: Boolean):this(name){
this.b=b
}
}
构造函数的继承
1 无主构造函数
class MyView : View(){
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
: super(context, attrs, defStyleAttr)
}
2.存在主构造函数
主构造函数一般实现基类型中参数最多的构造函数,参数少的构造函数则用 this 关键字引用即可了
class MyView(context: Context?, attrs: AttributeSet?, defStyleAttr: Int)
: View(context, attrs, defStyleAttr) {
constructor(context: Context?) : this(context,null,0)
constructor(context: Context?,attrs: AttributeSet?) : this(context,attrs,0)
}
构造函数的参数加上 var 和 val 是一种简洁的写法,意思是将该变量作为类的成员变量来使用:不是所有的构造函数都能用var和val修饰的,只有在主构造函数上才能使用,这只是声明属性以及从主构造函数初始化属性的一种简洁的语法。事实上你不能在次构造函数和其他函数上使用该语法,因为你不能在这些地方声明类的属性。