前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin | 10. 注解与反射

Kotlin | 10. 注解与反射

作者头像
Jingbin
发布2021-03-02 15:57:03
9340
发布2021-03-02 15:57:03
举报
文章被收录于专栏:Android 技术栈

本章内容包括:

  • 应用和定义注解
  • 在运行时使用反射对类进行自省
  • 一个真正的 Kotlin 项目实例

10.1 声明并应用注解

代码语言:javascript
复制
         /**-------------------------10.1.1 应用注解-------------------------*/

        @Deprecated("Use removeAt(index) instead.", ReplaceWith("removeAt(index)"))
        fun remove(index: Int) {
        }

        /*
        * 指定注解实参的语法与Java有些微小的差别:
        *  - 要把一个类指定为注解实参,在类名后加上 ::class:@MyAnnotation (MyClass:class)
        *  - 要把另一个注解指定为一个实参,去掉直接名称前面的 @。
        *  - 要把一个数组指定为一个实参,使用arrayOf函数:@RequestMapping(path = arrayOf("/foo","/bar"))。
        */


//        @Test(timeout = 100L)
//        fun testMethod() {
//        }

        /**-------------------------10.1.2 注解目标-------------------------*/

        /*
        * @get : Rule
        *
        * @get 使用点目标
        * Rule 注解名称
        */

        /*
        class HasTempFolder{
            // 注解的是 getter 而不是属性
            @get :Rule
            val folder = TemporaryFiolder()
        }*/

        /*
        * Kotlin 支持的使用点目标的完整列表如下:
        *  - property  -- Java的注解不能应用这种使用点目标
        *  - field     -- 为属性生成的字段
        *  - get       -- 属性的getter
        *  - set       -- 属性的setter
        *  - receiver  -- 扩展函数护着扩展属性的接收者参数
        *  - param     -- 构造方法的参数
        *  - setparam  -- 属性setter的参数
        *  - delegate  -- 为委托属性存储委托实例的字段
        *  - file      -- 包含在文件中声明的顶层函数和属性的类
        *
        * 用注解控制 JAVA API
        *  - @JvmName       将改变由Kotlin生成的Java方法或字段的名称
        *  - @JvmStatic     能被用在对象声明合作和伴生对象的方法上,把它们暴露成Java的静态方法
        *  - @JvmOverloads  指导Kotlin编译器为带默认参数值的函数生成多个重载(函数)
        *  - @JvmField      可以应用于一个属性,把这个属性暴露成一个没有访问器的共有Java字段
        */


        /**-------------------------10.1.3 使用注解订制 JSON 序列化-------------------------*/
        /*
        *  @JsonExclude 注解用来标记一个属性,这个属性应该排除在序列化和反序列化之外。
        *  @JsonName    注解让你说明代表这个属性的(JSON)键值对之中的键应该是一个给定的字符串,而不是属性的名称。
        */
//        data class Person(@JsonName("alias") val firstName: String, @JsonExclude val age: Int? = null)


        /**-------------------------10.1.4 声明注解-------------------------*/
        // 对拥有参数的注解来说,在类的主构造方法中声明这些参数:
//        annotation class JsonName(val name:String)

        /*Java中声明同样的注解:*/
//        public @ interface JsonName {String value(); }


        /**-------------------------10.1.5 元注解:控制如何处理一个注解-------------------------*/
        // 可以应用到注解类上的注解被称为 元注解。

        // @ Target 元注解说明了注解可以被应用的元素类型。
//        @Target(AnnotationTarget.PROPERTY_CLASS)
//        annotation class JsonExclude

        /*
        *  @Retention 元注解:
        * 说明你声明的注解是否会存储到.class 文件,以及在运行时是否可以通过反射来访问它。
        * Java 默认会在运行时存在,所以Kotlin的默认行为不同:注解拥有RUNTIME保留期。
        * */

        /**-------------------------10.1.6 使用类做注解参数-------------------------*/
        /*
        interface Company {
            val name: String
        }

        data class CompanyImpl(override val name: String) : Company
        data class Person(
                val name: String,
                @DeserializeInterface(CompanyImpl::class) val company: Company
        )

        annotation class DeserializeInterface(val targetClass: KClass<out Any>)
        */

        /**-------------------------10.1.7 使用泛型类做注解参数-------------------------*/

        // @CustomSerializer 注解接收一个自定义序列化器类的引用作为实参。这个序列化器类应该实现 ValueSerializer 接口:
//        interface ValueSerializer<T> {
//            fun toJsonValue(value: T): Any?
//        }

10.2 反射:在运行时对Kotlin对象进行自身

代码语言:javascript
复制
        /**-------------------------10.2.1 Kotlin反射API:KClass、KCallable、KFunction、和KProperty-------------------------*/

        // 从Java切换到Kotlin的反射API:
        class Person(val name: String, val age: Int)

        val person = Person("jingbin", 28)
        val kClass = person.javaClass.kotlin// 返回一个 KClass<Person> 的实例
        println(kClass.simpleName)// Person
        kClass.memberProperties.forEach { println(it.name) }// age name

        // 如何通过反射使用call来调用一个函数
//        interface KCallable<out R> {
//            fun call(vararg age: Any?): R
//        }

        fun foo(x: Int) = println(x)
        val kFunction = ::foo
        kFunction.call(42)

        /**-------------------------10.2.2 用反射实现对象序列化-------------------------*/
        // 代码清单10.1 序列化一个对象
//        private fun StringBuilder.serializeObject(obj: Any) {
//            // 取得对象的 XClass
//            val kClass = obj.javaClass.kotlin
//            // 取得类的所有属性
//            val properties = kClass.memberProperties
//
//            properties.joinToStringBuilder(this, prefix = "{", postfix = "}") { prop ->
//                // 取得属性名
//                serializeString(prop.name)
//                append(": ")
//                // 取得属性值
//                serializePropertyValue(prop.get(obj))
//            }
//        }

        /**-------------------------10.2.3 用注解订制序列化-------------------------*/
        // 代码清单10.2 使用属性过滤序列化对象
//        private fun StringBuilder.serializeObject(obj: Any) {
//        obj.javaClass.kotlin.memberProperties
//                .filter { it.findAnnotation<JsonExclude>() == null }
//                .joinToStringBuilder(this, prefix = "{", postfix = "}") {
//                    serializeProperty(it, obj)
//                }
//        }

        // 代码清单10.3 序列化单个属性
//        private fun StringBuilder.serializeProperty(prop: KProperty1<Any, *>, obj: Any) {
//            val jsonNameAnn = prop.findAnnotation<JsonName>()
//            val propName = jsonNameAnn?.name ?: prop.name
//            append(": ")
//            serializePropertyValue(prop.get(obj))
//        }

        // 代码清单10.4 取回属性值的序列化器
        // 代码清单10.5 序列化属性,支持自定义序列化器

        /**-------------------------10.2.4 JSON解析和对象反序列化-------------------------*/
        // 代码清单10.6 JSON解析器回调接口
        // 代码清单10.7 从JSON数据创建对象的接口
        // 代码清单10.8 顶层反序列化函数
        // 代码清单10.9 反序列化一个对象

        /**--------10.2.5 反序列化的最后一步:callBy()和使用反射创建对象-------------------------*/
        // 代码清单10.10 根据值类型取得序列化器
        // 代码清单10.11 Boolean值的序列化器
        // 代码清单10.12 缓存的反射数据的存储
        // 代码清单10.13 构造方法的参数及注解数据的缓存
        // 代码清单10.14 验证需要的参数被提供了

总结

  • Kotlin 中应用注解的语法和 Java 几乎一模一样。
  • 在Kotlin 中可以让你应用注解的目标的范围比 Java 更广,其中包括了文件和表达式。
  • 一个注解的参数可以是一个基本数据类型、一个字符串、一个枚举、一个类引用、一个其他注解类的实例,或者前面这些元素组成的数组。
  • 如果单个 Kotlin 声明产生了多个字节码元素,像@get Rule 这样指定一个注解的使用点目标,允许你选择注解如何应用。
  • 注解类的声明是这样的,它是一个拥有主构造方法且没有类主体的类,其构造方法中所有参数都被标记成 val 属性。
  • 元注解可以用来指定(使用点)目标、保留期模式和其他注解的特性。
  • 反射 API 让你在运行时动态地列举和访问一个对象的方法和属性。它拥有许多接口来表示不同种类的声明,例如类( KClass )、函数( KFunctio川等。
  • 要获取一个 KClass 的实例,如果类是静态己知的,可以使用 ClassName::class :否则,使用 obj.javaClass kotlin 从对象实例上取得类。
  • KFunction 接口和 KProperty 接口都继承了 KCallable ,它提供了 通用的 call 方法。
  • KCallable. callBy 方法能用来调用带默认参数值的方法。
  • KFunctionO、KFunctionl 等这种不同参数数量的函数可以使用 invoke方法调用。
  • KPropertyO 和 KPropertyl 是接收者数量不同的属性,支持用 get 方法取回值。KMutablePropertyO 和 KMutableProperty1 继承了这些接口。支持通过 set 方法来改变属性的值。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 10.1 声明并应用注解
  • 10.2 反射:在运行时对Kotlin对象进行自身
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档