高级安卓工程师面试题答案,Kotlin学习手记,吃透这份Android高级工程师面试497题解析

val deepCopiedPerson = person.deepCopy()

println(person === copiedPerson) //false

println(person === deepCopiedPerson) //false

println(person.group === copiedPerson.group) //true for shallow copy.

println(person.group === deepCopiedPerson.group) //false

println(deepCopiedPerson)

}

上面的例子中主要有几点需要注意的:

  • this::class.isData 判断是否是数据类 data class

  • this::class.primaryConstructor 获取主构造器,因为是数据类一定有主构造器,所以可以强转 !!

  • primaryConstructor.parameters let里面调用当前primaryConstructor对象的parameters获取所有的构造器参数

  • this::class as KClass<T> 逆变转协变,否则this.class返回一个协变点out T, 而get()方法接受一个逆变点,会报错

  • memberProperties.first { it.name == parameter.name } 数据类的特点是构造器的参数名和成员的属性名相等

  • parameter.type.classifier as? KClass<*> type参数需要调用classifier先转成KClass然后再判断是否是数据类

  • parameter to value?.deepCopy() 如果value是数据类继续调用value的deepCopy()方法深拷贝,这里是一个递归调用,K to V 是返回的一个 Pair对象

  • .toMap() 将Pair集合转Map集合

  • .let(primaryConstructor::callBy) 调用主构造器,callsBy是KCallable接口的方法,KFunction是KCallable的子类,因此所有的KFunction都可以调用callBy,callBy接受一个map参数正好就是let前面返回的结果。

这个例子有一个完整的开源库代码 KotlinDeepCopy 是由我参阅的学习资料的大神Bennyhuo所写的,但是貌似目前没什么issue, 慎用,可以当案例学习一下。

实例:实现 Model 映射

这个例子是实现一个拷贝工作,将一个对象里的字段赋值给另一个对象里面的同名字段,跟深拷贝的例子有点相似

//任意对象转其他对象(成员属性名相同)

inline fun <reified From : Any, reified To : Any> From.mapAs(): To {

//所有成员转成Map集合再调用下面的Map转对象方法即可

return From::class.memberProperties.map { it.name to it.get(this) }

.toMap().mapAs()

}

//Map转对象(成员属性名相同) 默认只处理数据类

inline fun Map<String, Any?>.mapAs(): To {

//primaryConstructor反射调用主构造器

return To::class.primaryConstructor!!.let {

it.parameters.map {

parameter ->

// this[parameter.name] 有可能为null, 如果目标对象To的构造器参数类型可以接受null类型就直接返回一个null 否则抛异常

parameter to (this[parameter.name] ?: if(parameter.type.isMarkedNullable) null

else throw IllegalArgumentException(“${parameter.name} is required but missing.”))

}.toMap()

.let(it::callBy)//callBy调用主构造器构造出一个To类型的对象

}

}

第一个方法的实现实际上是调用第二个方法的,所以只需实现第二个方法即可,这里依然是先获取主构造器To::class.primaryConstructor,获取了主构造器之后拿到它的参数列表进行map操作,map里面依然是返回当前参数 parameter to value,to 操作符左边的是To对象的也就是目标对象, to 操作符右边的是当前调用.mapAs的map对象,因此通过this[parameter.name]访问它里面的同名参数的value值,但是这个值可能为null, 不为null就返回 ?: 左边它自身,为null还需一个处理就是如果To类型即目标类的构造函数的这个当前参数可接受可空类型 ,就直接传null, 否则抛异常。

调用测试代码:

data class UserVO(val login: String, val avatarUrl: String)

data class UserDTO(

var id: Int,

var login: String,

var avatarUrl: String,

var url: String,

var htmlUrl: String

)

fun main() {

val userDTO = UserDTO(

0,

“world”,

“https://ccccccc”,

“https://ddddddddd”,

“https://eeeeeeeeeee”

)

val userVO: UserVO = userDTO.mapAs()

println(userVO)

val userMap = mapOf(

“id” to 0,

“login” to “hello”,

“avatarUrl” to “https://aaaaaaa”,

“url” to “https://bbbbbbbb”

)

val userVOFromMap: UserVO = userMap.mapAs()

println(userVOFromMap)

}

实例:可释放对象引用的不可空类型

这个例子主要是模仿了一个Android当中释放bitmap对象赋值为null的场景,在kotlin当中如果你定义了一个 var bitmap: Bitmap, 然后在onDestroy方法里面将其置为null, 但是这样写bitmap=null是不行的,因为定义的时候是一个不可空类型,这就矛盾了。

fun releasableNotNull() = ReleasableNotNull()

class ReleasableNotNull<T: Any>: ReadWriteProperty<Any, T> {

private var value: T? = null

override fun getValue(thisRef: Any, property: KProperty<*>): T {

return value ?: throw IllegalStateException(“Not initialized or released already.”)

}

override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {

this.value = value

}

fun isInitialized() = value != null

fun release() {

value = null

}

}

inline val KProperty0<*>.isInitialized: Boolean

get() {

//允许反射获取

isAccessible = true

//this.getDelegate()获取属性代理的实例

return (this.getDelegate() as? ReleasableNotNull<*>)?.isInitialized()

?: throw IllegalAccessException(“Delegate is not an instance of ReleasableNotNull or is null.”)

}

fun KProperty0<*>.release() {

isAccessible = true

(this.getDelegate() as? ReleasableNotNull<*>)?.release()

?: throw IllegalAccessException(“Delegate is not an instance of ReleasableNotNull or is null.”)

}

class Bitmap(val width: Int, val height: Int)

class Activity {

private var bitmap by releasableNotNull()

fun onCreate(){

//::bitmap省略了this, 默认绑定了当前对象为receiver

println(this::bitmap.isInitialized)

println(this::bitmap.isInitialized)

bitmap = Bitmap(1920, 1080)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

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

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

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

尾声

最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些 Kotlin 高级面试供您参考: 1. 什么是内联函数?为什么使用内联函数? 内联函数是一种特殊的函数,它将函数调用替换为函数体本身。在 Kotlin 中,使用 inline 关键字声明内联函数。使用内联函数可以减少函数调用的开销,从而提高程序的性能。另外,内联函数还可以更好地支持函数式编程。 2. 什么是高阶函数? 高阶函数是一种能够接受其他函数作为参数或返回其他函数的函数。在 Kotlin 中,使用函数类型来表示函数,因此可以将函数作为参数传递给其他函数或从函数中返回另一个函数。 3. 解释协程是什么以及如何使用它们? 协程是一种轻量级的线程,它可以在单个线程中执行异步非阻塞操作。在 Kotlin 中,使用 suspend 关键字定义挂起函数,这些函数可以被协程使用。通过使用协程,可以编写更简洁、更可读、更可维护的异步代码。 4. 什么是委托? 委托是一种将对象的某些功能委托给另一个对象的机制。在 Kotlin 中,使用 by 关键字实现委托。例如,可以通过将属性的访问委托给另一个对象来实现装饰器模式。 5. 解释 Kotlin 中的类型推断是如何工作的? 在 Kotlin 中,类型推断是通过编译器自动推导变量或表达式的类型。如果编译器可以推断出变量或表达式的类型,则无需显式指定类型。类型推断有助于减少代码中的重复和冗余,从而提高代码的可读性和可维护性。 6. 什么是扩展函数? 扩展函数是一种将函数添加到现有类中的机制,而无需修改该类的源代码。在 Kotlin 中,使用扩展函数可以向任何类添加新的功能,从而提高代码的可重用性和可维护性。 7. 解释协变和逆变是什么,以及如何在 Kotlin 中使用它们? 协变和逆变是一种处理类型之间关系的机制。协变表示类型参数可以在子类中被放宽,逆变表示类型参数可以在子类中被收缩。在 Kotlin 中,使用 out 关键字实现协变,使用 in 关键字实现逆变。 8. Kotlin 中可以使用哪些设计模式? 在 Kotlin 中可以使用各种设计模式,包括工厂模式、单例模式、装饰器模式、观察者模式等等。Kotlin 的语法和特性使得实现这些模式变得更加简单和优雅。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值