constructor(view: View, index: Int) : this(view) {
views.add(view)
}
}
因为初始化块中的代码实际上是主构造方法的一部分,所以初始化代码块会在次构造方法之前执行。
继承与覆盖
在Kotlin中,所有的类默认都是final的,如果你需要允许它可以被继承,那么你需要使用open声明:
open class Animal(age: Int) {
init {
println(age)
}
}
在 Kotlin 中所有类都有一个共同的超类 Any,Any 有三个方法:equals()、hashCode() 与 toString()
在Kotlin中继承用:如需继承一个类,请在类头中把超类放到冒号之后:
//派生类有柱构造方法的情况
class Dog(age: Int) : Animal(age)
如果派生类有一个主构造方法,其基类必须用派生类主构造方法的参数初始化。
如果派生类没有主构造方法,那么每个次构造方法必须使用 super 关键字初始化其基类型。
//派生类无柱构造方法的情况
class Cat : Animal {
constructor(age: Int) : super(age)
}
覆盖规则
覆盖方法
Kotlin的类成员默认是隐藏的,也就是无法被覆盖,如果要覆盖我们需要用到显式修饰符(open):
open class Animal(age: Int) {
init {
println(age)
}
open fun eat() {
}
}
/**
- 继承
*/
//派生类有主构造方法的情况
class Dog(age: Int) : Animal(age) {
override fun eat() {
}
}
eat() 方法上必须加上 override 修饰符。如果没写,编译器将会报错。 如果方法没有标注 open 如 eat(),那么子类中不允许定义相同签名的方法, 不论加不加 override。
覆盖属性
属性覆盖与方法覆盖类似;在超类中声明然后在派生类中重新声明的属性必须以override 开头,并且它们必须具有兼容的类型。
open class Animal(age: Int) {
open val foot: Int = 0
}
class Dog(age: Int) : Animal(age) {
override val foot = 4
}
属性
属性的声明
Kotlin 类中的属性既可以用关键字 var 声明为可变的,也可以用关键字 val 声明为只读的。
class Shop {
var name: String = “Android”
var address: String? = null
}
fun copyShop(shop: Shop): Shop {
val shop = Shop()
shop.name = shop.name
shop.address = shop.address
// ……
return shop
}
Getters 与 Setters
声明一个属性的完整语法是
var [: ] [= <property_initializer>]
[]
[]
其初始器(initializer)、getter 和 setter 都是可选的。如果属性类型可以从初始器 (或者从其 getter 返回值)中推断出来,也可以省略。
案例1:
val simple: Int? // 类型 Int、默认 getter、必须在构造方法中初始化
案例2:
我们可以为属性定义自定义的访问器。如果我们定义了一个自定义的 getter,那么每次访问该属性时都会调用它:
val isClose: Boolean
get() = Calendar.getInstance().get(Calendar.HOUR_OF_DAY) > 11
如果我们定义了一个自定义的 setter,那么每次给属性赋值时都会调用它。一个自定义的 setter 如下所示:
var score: Float = 0.0f
get() = if (field < 0.2f) 0.2f else field * 1.5f
set(value) {
println(value)
}
延迟初始化属性
通常属性声明为非空类型必须在构造方法中初始化。 然而,这经常不方便。例如:属性可以通过依赖注入来初始化, 或者在单元测试的 setup 方法中初始化。
为处理这种情况,你可以用 lateinit 修饰符标记该属性:
class Test {
lateinit var shop: Shop
fun setup() {
shop = Shop()
}
}
在初始化前访问一个 lateinit 属性会抛出一个特定异常。
我们可以通过属性的 .isInitialized API来检测一个 lateinit var 属性是否已经初始化过:
if (::shop.isInitialized)
println(shop.address)
抽象类与接口
抽象类
类以及其中的某些成员可以声明为 abstract:
abstract class Printer {
abstract fun print()
}
class FilePrinter : Printer() {
override fun print() {
}
}
接口
Kotlin 的接口可以既包含抽象方法的声明也包含实现。与抽象类不同的是,接口无法保存状态,它可以有属性但必须声明为抽象或提供访问器实现。
可以将Kotlin的接口理解为特殊的抽象类
接口的定义与实现
interface Study {
var time: Int// 抽象的
fun discuss()
fun earningCourses() {
println(“Android 架构师”)
}
}
//在主构造方法中覆盖接口的字段
class StudyAS(override var time: Int) : Study {
//在类体中覆盖接口的字段
// override var time: Int = 0
override fun discuss() {
}
}
解决覆盖冲突
实现多个接口时,可能会遇到同一方法继承多个实现的问题:
interface A {
fun foo() {
println(“A”)
}
}
interface B {
fun foo() {
print(“B”)
}
}
class D : A, B {
override fun foo() {
super.foo()
super.foo()
}
}
在上例中我们通过super<>.来解决覆盖冲突的问题。
数据类
我们经常创建一些只保存数据的类,在 Kotlin 中,我们可以通过data来声明一个数据类:
data class Address(val name: String, val number: Int) {
var city: String = “”
fun print() {
println(city)
}
}
数据类的要求
- 主构造方法需要至少有一个参数;
- 主构造方法的所有参数需要标记为 val 或 var;
- 数据类不能是抽象、开放、密封或者内部的;
数据类与解构声明
为数据类生成的 Component 方法 使它们可在解构声明中使用:
val address = Address(“Android”, 1000)
address.city = “Beijing”
val (name, city) = address
println(“name:
n
a
m
e
c
i
t
y
:
name city:
namecity:city”)
对象表达式与对象声明
在Kotlin中提供了对象表达式来方面我们在需要对一个类做轻微改动并创建它的对象,而不用为之显式声明新的子类。
对象表达式
结尾
好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,可以来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。
这里放上一部分我工作以来以及参与过的大大小小的面试收集总结出来的一套进阶学习的视频及面试专题资料包,在这里免费分享给大家,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
https://github.com/a120464/Android-P7/blob/master/Android%E5%BC%80%E5%8F%91%E4%B8%8D%E4%BC%9A%E8%BF%99%E4%BA%9B%EF%BC%9F%E5%A6%82%E4%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)给大家,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
[外链图片转存中…(img-BhIWV6dl-1643959434791)]