从Java到Kotlin(七)

作者: 四会歌神陈子豪 | 来源:发表于2018-03-02 18:04 被阅读88次

    反射和注解

    目录

    • 1.反射
      1.1类引用
      1.2函数引用
      1.3属性引用
    • 2.注解
      2.1声明注解
      2.2构造函数

    1.反射

    反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    Kotlin中使用反射功能所需的运行时组件作为单独的 JAR 文件(kotlin-reflect.jar)分发。这样做是为了减少不使用反射功能的应用程序所需的运行时库的大小。如果用Android Studio运行Kotlin项目,一般会在创建工程时,自动引入(kotlin-reflect.jar)

    1.1类引用

    • Java代码
    //方式一
    Class<?> clazz = User.class;
    //方式二
    Class<?> clazz = Class.forName("包名.User");
    
    • Kotlin代码
    //如果User是Kotlin的类
     var user = User::class
    //如果User是Java的类
     var user = User::class.java
    

    在Kotlin中,用类名+两个冒号::+class(如果是java类要在后面加上.java)表示获取这个类的对象。

    1.2函数引用

    • Java代码
    public class User {
        private String userName;
    
        public User(String userName) {
            super();
            this.userName = userName;
        }
    
        public void printUserName() {
            System.out.println(userName);
        }
    }
    
    //获取User对象
    Class<?> clazz = Class.forName("com.demo.czh.myapplication.User");
    //获取带String参数的public构造函数
    Constructor c=clazz.getDeclaredConstructor(String.class);
    //创建User对象的实例
    User user = (User) c.newInstance("Czh");
    //根据方法名"printUserName"获取 method 对象
    Method method = clazz.getDeclaredMethod("printUserName");
    //通过 method 调用 invoke()方法,调用User里的 printUserName
    method.invoke(user);
    
    运行代码,得到结果:
    • Kotlin代码
    class User(var userName: String) {
        fun printUserName() {
            println(userName)
        }
    }
    
    //方式一
    //获取printUserName函数对象
    var p = User::printUserName
    //调用invoke()函数执行printUserName函数
    p.invoke(User("Czh"))
    
    //方式二
    //利用Java反射机制调用getMethod()方法,并指定方法名字"printUserName"
    var method = User::class.java.getMethod("printUserName")
    //调用invoke()函数
    method.invoke(User("Czh"))
    
    运行代码,得到结果:

    在Kotlin中,可以用类名+两个冒号::+函数名直接获取这个函数的对象;或者利用Java反射机制调用getMethod()方法来获取函数的对象。

    1.3属性引用

    • Java代码
    public class User {
        public String userName;
    }
    
    //获取User对象
    Class<?> clazz = Class.forName("com.demo.czh.myapplication.User");
    //创建User对象的实例
    User user = (User) clazz.newInstance();
    //获取Field对象并指定属性名为"userName"
    Field field = clazz.getField("userName");
    //通过set()方法给userName赋值
    field.set(user, "Czh");
    //通过get()方法获取userName的值
    System.out.println(field.get(user));
    
    运行代码,得到结果:
    • Kotlin代码
    class User {
        var userName: String = "Czh"
            get() = field
            set(value) {
                field = value
            }
    }
    
    //方式一
    var user = User()
    //获取属性对象
    var userName = User::userName
    println(userName.get(user))
    //设置属性值
    userName.set(user, "James")
    //获取属性值
    println(userName.get(user))
    
    //方式二
    //利用Java反射机制获取getUserName方法
    var getName = User::class.java.getMethod("getUserName")
    //利用Java反射机制获取setUserName方法
    var setName = User::class.java.getMethod("setUserName", java.lang.String().javaClass)
    //设置属性值
    setName.invoke(user, "Harden")
    //获取属性值
    println(getName.invoke(user))
    

    运行代码,得到结果:


    在Kotlin中,可以用类名+两个冒号::+属性名直接获取属性对象;或者通过Java反射机制获取属性的get/set方法来获取或修改属性值。

    2.注解

    2.1注解声明

    Java声明注解

    public @interface MyAnnotation {
    }
    

    Kotlin声明注解

    annotation class MyAnnotation
    

    注解的附加属性可以通过用元注解标注注解类来指定:

    • @Target 指定可以用该注解标注的元素的可能的类型(类、函数、属性、表达式等);
    • @Retention 指定该注解是否存储在编译后的 class 文件中,以及它在运行时能否通过反射可见 (默认都是 true);
    • @Repeatable 允许在单个元素上多次使用相同的该注解;
    • @MustBeDocumented 指定该注解是公有 API 的一部分,并且应该包含在生成的 API 文档中显示的类或方法的签名中。

    Java添加元注解

    @Target(ElementType.METHOD)//表示可以在方法中使用
    @Retention(RetentionPolicy.RUNTIME)//表示运行时注解
    public @interface MyAnnotation {
    }
    

    Kotlin添加元注解

    @Target(AnnotationTarget.FUNCTION)//表示可以在函数中使用
    @Retention(AnnotationRetention.RUNTIME)//表示运行时注解
    annotation class MyAnnotation
    

    2.2构造函数

    注解类可以带有构造函数

    • Kotlin代码
    annotation class MyAnnotation(val value: Int)
    
    //使用
    @MyAnnotation(1)
    class Foo {
    }
    
    • Java代码
    public @interface MyAnnotation {
        int value();
    }
    
    //使用
    @MyAnnotation(1)
    public class Foo {
    }
    

    注解类的构造函数只允许下列参数类型:

    • 对应于 Java 原生类型的类型(Int、 Long等);
    • 字符串;
    • 类(Foo::class);
    • 枚举;
    • 其他注解;
    • 上面已列类型的数组。
    • Kotlin中只允许用val声明参数
    • 当参数类型是其他注解时,该注解类的名字前面不能用@

    总结

    注解和反射都是很多应用中使用到的技术,而本篇文章主要对比了注解和反射在Java和Kotlin中写法的差别。

    参考文献:
    Kotlin语言中文站、《Kotlin程序开发入门精要》\

    推荐阅读:
    从Java到Kotlin(一)为什么使用Kotlin
    从Java到Kotlin(二)基本语法
    从Java到Kotlin(三)类和接口
    从Java到Kotlin(四)对象与泛型
    从Java到Kotlin(五)函数与Lambda表达式
    从Java到Kotlin(六)扩展与委托
    从Java到Kotlin(八)Kotlin的其他技术
    Kotlin学习资料汇总


    更多精彩文章请扫描下方二维码关注微信公众号"AndroidCzh":这里将长期为您分享原创文章、Android开发经验等!
    QQ交流群: 705929135

    相关文章

      网友评论

        本文标题:从Java到Kotlin(七)

        本文链接:https://www.haomeiwen.com/subject/aowwoxtx.html