Kotlin学习(12)元编程、注解与反射(1),字节android面试

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

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

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

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

注解是把元数据信息直接写在了源代码中,而不是保存在外部文件中。

注解将元数据附加到代码中。而反射可以在运行时把代码中的注解元数据获取到,并在目标代码执行之前进行动态代理,实现业务逻辑的动态注入,这其实就是AOP的核心思想----通过运行期动态代理实现不修改源码的情况下,给程序动态添加新功能的一种技术。

2. 注解


Kotlin的注解跟Java的注解完全兼容。

2.1 声明注解

在Kotlin中声明注解使用 annotation class关键字,例如,我们要声明两个注解 Run 和 TestCase 如下:

@Target(

AnnotationTarget.CLASS,

AnnotationTarget.FUNCTION,

AnnotationTarget.VALUE_PARAMETER,

AnnotationTarget.EXPRESSION

)

@Retention(AnnotationRetention.SOURCE)

@Repeatable

@MustBeDocumented

annotation class TestCase(val id: String)

@Target(AnnotationTarget.CLASS,

AnnotationTarget.FUNCTION,

AnnotationTarget.VALUE_PARAMETER,

AnnotationTarget.EXPRESSION)

@Retention(AnnotationRetention.SOURCE)

@Repeatable

@MustBeDocumented

annotation class Run

从这个关键字上可以看出注解也是一种class,编译器同样可以对注解类型在编译器进行类型检查。

自定义的注解中使用的注解,称之为元注解。通过向注解类添加元注解的方式来指定其他属性。元注解说明如表:

| 元注解名称 | 功能说明 |

| — | — |

| @Target | 指定这个注解可被用于哪些元素 ( 这些元素定义在kotlin.annotation.AnnotationTarget 枚举类中。它们是:类 CLASS, 注解类 ANNOTATION_CLASS,泛型参数 TYPE_PARAMETER,函数 FUNCTION, 属性 PROPERTY, 用于描述域成员变量的 FIELD,局部变量 LOCAL_VARIABLE,VALUE_PARAMETER,CONSTRUCTOR,PROPERTY_GETTER,PROPERTY_SETTER, 用于描述类、接口(包括注解类型) 或enum声明的 TYPE, 表达式 EXPRESSION,文件 FILE,类型别名TYPEALIAS等 |

| @Retention | 指定这个注解的信息是否被保存到编译后的 class 文件中, 以及在运行时是否可以通过反射访问到它, 可取的枚举值有3个,分别是: SOURCE (注解数据不存储在二进制输出),BINARY(注解数据存储在二进制输出中, 但反射不可见), RUNTIME(注解数据存储在二进制输出中, 可用于反射 (默认值 ) |

| @Repeatable | 允许在单个元素上多次使用同一个注解 |

| @MustBeDocumented | 表示这个注解是公开 API 的一部分, 在自动产生的 API 文档的类或者函数签名中, 应该包含这个注解的信息。 |

2.2 使用注解

上面我们声明了Run注解,它可以使用在 CLASS、FUNCTION、VALUE_PARAMETER和EXPRESSION上,我们这里给出的示例使用在类上:

@Run

class SwordTest()

我们声明的 TestCase注解有个构造函数,传入的参数时一个String类型的ID,把这个注解用在函数上:

@Run

class SwordTest() {

@TestCase(id = “a”)

fun testCase(testId: String) {

println(“Run SwordTest Id = $testId”)

}

}

上面是注解在代码中的简单使用示例。其中的 @TestCase(id=“a”)是注解构造函数的使用。

注解可以带有参数的构造器。注解参数可支持的数据类型如下:

  • 基本数据类型

  • String

  • KClass

  • enum

  • Annotation

  • 上面的除了基本数据类型为引用的 数组

下面两种声明是不会通过的

annotation class TestCase1(val id: Array)

annotation class TestCase2(val id: SwordTest)

另外需要注意的是,注解类型中不能有null,因为 JVM不支持将null作为注解属性的值进行存储。

如果注解用作另一个注解的参数时,则其名称不能以 @字符作为前缀。

例如:

annotation class AnnoX(val value: String)

annotation class AnnoY(

val message: String

val annoX: AnnoX = AnnoX(“X”))

2.3 处理注解

如果没有相应的注解信息处理逻辑流程,那么注解可以说是废了,没有什么实用价值。

首先,我们的目标测试类是:

@Run

class SwordTest() {

@TestCase(id = “a”)

fun testCase(testId: String) {

println(“Run SwordTest Id = $testId”)

}

}

我们需要在 @TestCase注解作用在函数上的处理过程

  1. ::class 引用

首先声明一个变量指向SwordTest实例

然后就可以通过这个变量来获取该对象的类的信息,使用 ::class来获取 sword对象实例的 KClass类的引用

val sword = SwordTest()

val kClass = sword::class

//有点像Java中的 getClass()

//上面这行代码,Kotlin编译器会自动推断出 kClass变量的类型是

val kClass:KClass = sword::class

  1. members扩展属性

下面我们需要获取 sword对象类型所声明的所有函数。Kotlin中 可以直接使用扩展属性 declaredFunctions来获取这个类中声明的所有函数。

//返回的是一个 Collection<KCallable<>> 其中是Koltlin泛型中的星投影

val members = kClass.members

  1. annotations属性

KFunction 类型继承了 KCallable,KCallable又继承了 KAnnotatedElement。KAnnotatedElement中有个public val annotations:List属性里存储了该函数所有的注解信息。通过遍历这个存储Annotation的List,可以获取到TestCase注解:

for (f in members ) {

f.annotations.forEach {

if(it is TestCase){

val id = it.id //TestCase 注解的属性ID

doSomething(id) //注解处理逻辑

}

}

}

  1. call函数

另外,如果想通过反射来调用函数,可以直接使用 call():

f.call(sword, id)

//等价于

f.javaMethod?.invoke(sword, id)

//到这里,我们就完成了一个简单的注解处理器,完整的代码如下:

@Target(

AnnotationTarget.CLASS,

AnnotationTarget.FUNCTION,

AnnotationTarget.VALUE_PARAMETER,

AnnotationTarget.EXPRESSION

)

@Retention(AnnotationRetention.SOURCE)

@Repeatable

@MustBeDocumented

annotation class TestCase(val id: String)

class SwordTest {

@TestCase(id = “a”)

fun testCase(testId: String) {

println(“Run SwordTest Id = $testId”)

}

}

fun testAnnoProcessing() {

val sword = SwordTest()

val kClass = sword::class

val members = kClass.members

for (f in members) {

f.annotations.forEach {

if (it is TestCase) {

val id = it.id

doSomething(id)

f.call(sword, id)

}

}

}

}

private fun doSomething(id: String) {

println(“Do Something in Annotation Processing $id ${System.currentTimeMillis()}”)

}

//测试:

main(){

testAnnoProcessing()

}

3. 反射


在Kotlin中我们有两种方式来实现反射功能。

一种是调用Java的反射包下的API

另外一种是 直接调用Kotlin语言提供的 kotlin.reflect包下面的API

不过因为反射功能的应用场景并非所有编程场景都会用到,所以Kotlin把 kotlin.reflect包放到了单独的 kotlin-reflect-1.1.xx.jar下面,也就是说我们如果要使用Kotlin的反射Api,还要去添加依赖。

3.1 类引用

我们先定义一个代码实例:

open class BaseContainer

class Container<T : Comparable> : BaseContainer {

val elements: MutableList

constructor(elements: MutableList) {

this.elements = elements

}

fun sort(): Container {

elements.sort()

return this

}

override fun toString(): String {

return “Container(elements = $elements)”

}

}

反射是在陨石时获取一个类引用。我们已经知道使用 ::class 可以获取到当前对象KClass对象。

val container = Container(mutableListOf(1, 3, 2, 5, 4, 7, 6))

val kClass = container::class

//如果是要使用Java中的类引用,就要使用javaClass

val jClass = container.javaClass

//或者使用KClass实例的.java属性

val jkClass = kClass.java

3.2 函数引用

例如,有一个简单地判断一个Int整数是否是奇数的函数:

尾声

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

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

这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

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

架构篇

《Jetpack全家桶打造全新Google标准架构模式》

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

-OZsXJiLZ-1713561229410)]

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

[外链图片转存中…(img-0ksI9kps-1713561229410)]

架构篇

《Jetpack全家桶打造全新Google标准架构模式》
[外链图片转存中…(img-K26BDxw2-1713561229411)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-MfCx6gZf-1713561229411)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值