Kotlin(五)深入理解Kotlin类与接口

class InitDemo(name: String) {
/**

  • 关于:.also(::println)的理解
  • ::表示创建成员引用或类引用,通过它来传递println方法来作为also的参数
  • 那also又是什么呢?源码跟进 -> Kotlin扩展
    */
    val firstProp = “First Prop: $name”.also(::println)

init {
println(“First initializer block that prints $name”)
}

val secondProp = “Second Prop: ${name.length}”.also(::println)

init {
println(“Second initializer block that prints ${name.length}”)
}
}

主构造的参数除了可以在初始化块中使用外,还可以在类体内声明属性时使用。

声明属性以及从主构造方法初始化属性的更简洁的写法:

//构造方法的参数作为类的属性并赋值,KotlinClass2在初始化时它的name与score属性会被赋值
class KotlinClass2(val name: String, var score: Int) { /……/ }

与普通属性一样,主构造方法中声明的属性可以是可变的(var)或只读的(val)。

次构造方法

我们也可以在类体内通过constructor前缀来声明类的次构造方法:

class KotlinClass3 {
var views: MutableList = mutableListOf()

constructor(view: View) {
views.add(view)
}
}

如果类有一个主构造方法,每个次构造方法都需要委托给主构造方法,可以直接委托或者通过别的次构造方法间接委托。委托到另一个构造方法用 this 关键字即可:

class KotlinClass3(val view: View) {
var views: MutableList = mutableListOf()

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中提供了对象表达式来方面我们在需要对一个类做轻微改动并创建它的对象,而不用为之显式声明新的子类。

对象表达式

要创建一个继承自某个(或某些)类型的匿名类的对象,我们会这么写:

open class Address2(name: String) {
open fun print() {

}
}

class Shop2 {
var address: Address2? = null
fun addAddress(address: Address2) {
this.address = address
}

}

fun test3() {
//如果超类型有一个构造方法,则必须传递适当的构造方法参数给它
Shop2().addAddress(object : Address2(“Android”) {
override fun print() {
super.print()
}
})
}

如果我们只需要“一个对象而已”,并不需要特殊超类型,那么我们可以简单地写:

fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

资源分享

一线互联网面试专题

379页的Android进阶知识大全

379页的Android进阶知识大全

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

2020年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

zjK2D-1712288029784)]

[外链图片转存中…(img-5XimeP6E-1712288029784)]

[外链图片转存中…(img-iT964ztm-1712288029785)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

2020年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值