Kotlin中的反射机制深入讲解

前言

Java中的反射机制,使得我们可以在运行期获取Java类的字节码文件中的构造函数,成员变量,成员函数等信息。这一特性使得反射机制被常常用在框架中,想要比较系统的了解Kotlin中的反射,先从Java的反射说起。

Java中的反射

通常我们写好的.java源码文件,经过javac的编译,最终生成了.class字节码文件。这些字节码文件是与平台无关的,使用时通过Classloader去加载这些.class字节码文件,从而让程序按照我们编写好的业务逻辑运行。Java的反射主要是从这些.class文件中获取我们想要得到的内容,那么Java中的反射能够得到哪些内容呢?

获取Class对象

Java是面向对象的语言,同样的.class字节码文件也不例外,想要获取.class文件中的内容,就要先获取.class文件对应的Class对象。Java中获取Class对象的方式有三种。

//1.Class.forName("类名字符串") (注意:类名字符串必须是全称,包名+类名)
Class baseInfo = Class.forName("top.sguotao.ReflectionJava");
 //2.类名.class
Class object = Object.class;
//3.实例对象.getClass()
Class date = (new Date()).getClass();
Class testclass = this.getClass();

获取类的构造函数Constructor

获取Class对象之后,就可以获取其中的构造函数,从而去创建实例对象。类的构造函数对应java.lang.reflect.Constructor。获取构造函数归纳起来有以下五种方式:

 // 1.获取参数列表是parameterTypes,访问控制符是public的构造函数
 public Constructor getConstructor(Class[] parameterTypes)

 // 2.获取所有访问控制符是public的构造函数
 public Constructor[] getConstructors()

 // 3.获取参数列表是parameterTypes,并且是类自身声明的构造函数,访问控制符包含public、protected和private的函数。
 public Constructor getDeclaredConstructor(Class[] parameterTypes)

 //4.获取类自身声明的全部的构造函数,访问控制符包含public、protected和private的函数。
 public Constructor[] getDeclaredConstructors()

 //5.如果类声明在其它类的构造函数中,返回该类所在的构造函数,如果存在则返回,不存在返回null
 public Constructor getEnclosingConstructor()

获取类的成员变量

类的成员变量对应的是java.lang.reflect.Field,获取成员变量归纳起来有以下四种方式:

 //1.获取“名称是name”的public的成员变量(包括从基类继承的、从接口实现的所有public成员变量)
 public Field getField(String name)

 //2.获取全部的public成员变量(包括从基类继承的、从接口实现的所有public成员变量)
 public Field[] getFields()

 //3.获取“名称是name”,并且是类自身声明的成员变量,包含public、protected和private成员变量。
 public Field getDeclaredField(String name)

 //4.获取全部的类自身声明的成员变量,包含public、protected和private成员变量。
 public Field[] getDeclaredFields()

获取类的成员函数

类的成员函数对应的是java.lang.reflect.Method,获取成员函数归纳起来有下面5种方式:

// 1.获取函数名是name,参数是parameterTypes的public的函数(包括从基类继承的、从接口实现的所有public函数)
 public Method getMethod(String name, Class[] parameterTypes)

 //2.获取全部的public的函数(包括从基类继承的、从接口实现的所有public函数)
 public Method[] getMethods()

 //3.获取函数名name,参数是parameterTypes,并且是类自身声明的函数,包含public、protected和private方法。
 public Method getDeclaredMethod(String name, Class[] parameterTypes)

 //4.获取全部的类自身声明的函数,包含public、protected和private方法。
 public Method[] getDeclaredMethods()

 //5.如果这个类是其它类中某个方法的内部类,调用getEnclosingMethod()就是这个类所在的方法;若不存在,返回null。
 public Method getEnclosingMethod()

获取类的其它信息

获取类的注解信息,对应的是java.lang.annotation.Annotation接口,获取类的注解信息归纳起来有下面3种方法:

//1.获取类的annotationClass类型的注解 (包括从基类继承的、从接口实现的所有public成员变量)
public Annotation<A> getAnnotation(Class annotationClass)

//2.获取类的全部注解 (包括从基类继承的、从接口实现的所有public成员变量)
public Annotation[] getAnnotations()

//3.获取类自身声明的全部注解 (包含public、protected和private成员变量)
public Annotation[] getDeclaredAnnotations()

获取类的接口和基类的信息,对应的是java.lang.reflect.Type接口,获取类的接口和基类信息有下面两个方法:

 // 获取实现的全部接口
public Type[] getGenericInterfaces()

// 获取基类
public Type getGenericSuperclass()

获取类的其它描述信息。

 //1.获取类名
 public String getSimpleName()

 //2.获取完整类名
 public String getName()

 //3.判断类是不是枚举类
 public boolean isEnum()

 //4.判断obj是不是类的实例对象
 public boolean isInstance(Object obj)

 //5.判断类是不是接口
 public boolean isInterface()

 //6.判断类是不是本地类,所谓本地类,就是定义在方法内部的类。
 public boolean isLocalClass()

 //7.判断类是不是成员类,所谓成员类,就是常见的内部类,是指不在代码块,构造函数和成员方法中的内部类。
 public boolean isMemberClass()

 //8.判断类是不是基本类型。 基本类型,包括void和boolean、byte、char、short、int、long、float 和 double这几种类型。
 public boolean isPrimitive()

Kotlin中的反射

在Kotlin中,字节码对应的类是kotlin.reflect.KClass,因为Kotlin百分之百兼容Java,所以Kotlin中可以使用Java中的反射,但是由于Kotlin中字节码.class对应的是KClass类,所以如果想要使用Java中的反射,需要首先获取Class的实例,在Kotlin中可以通过以下两种方式来获取Class实例。

//1.通过实例.javaClass
var hello = HelloWorld()
hello.javaClass

 //2.通过类Kclass类的.java属性
HelloWorld::class.java

获取了Class实例,就可以调用上面介绍的方法,获取各种在Java中定义的类的信息了。

当然Kotlin中除了可以使用Java中的反射以外,还可以使用Kotlin中声明的一些方法,当然同Java中反射一样,想要使用这些方法,先要获取Kclass对象,在Kotlin中可以通过以下两种方式获取Kclass实例。

 //1.通过类::class的方式获取Kclass实例
val clazz1: KClass<*> = HelloWorld::class
//2.通过实例.javaClass.kotlin获取Kclass实例
var hello = HelloWorld()
val clazz2 = hello.javaClass.kotlin

获取了Kclass实例之后,就可以调用Kotlin中声明的一些关于反射的方法了,那么都有哪些方法呢?

构造函数Constructor

Kotlin可以通过下面的方法,获取所有的构造函数。

//返回这个类的所有构造器
public val constructors: Collection<KFunction<T>>

成员变量和成员函数

Kotlin中获取成员变量和成员函数的方法有6个。

 //返回类可访问的所有函数和属性,包括继承自基类的,但是不包括构造器
 override val members: Collection<KCallable<*>>
 //返回类声明的所有函数
 val KClass<*>.declaredFunctions: Collection<KFunction<*>>
 //返回类的扩展函数
 val KClass<*>.declaredMemberExtensionFunctions: Collection<KFunction<*>>
 //返回类的扩展属性
 val <T : Any> KClass<T>.declaredMemberExtensionProperties: Collection<KProperty2<T, *, *>>
 //返回类自身声明的成员函数
 val KClass<*>.declaredMemberFunctions: Collection<KFunction<*>>
 //返回类自身声明的成员变量(属性)
 val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T, *>>

类相关信息

可以看到Kotlin反射中,可以获取比Java反射更多的关于类的信息。

//1.返回类的名字
public val simpleName: String?
 //2.返回类的全包名
public val qualifiedName: String?
//3.如果这个类声明为object,则返回其实例,否则返回null
public val objectInstance: T?
//4.返回类的可见性
@SinceKotlin("1.1")
public val visibility: KVisibility?
//5.判断类是否为final类(在Kotlin中,类默认是final的,除非这个类声明为open或者abstract)
@SinceKotlin("1.1")
public val isFinal: Boolean
//6.判断类是否是open的(abstract类也是open的),表示这个类可以被继承
@SinceKotlin("1.1")
public val isOpen: Boolean
//7.判断类是否为抽象类
@SinceKotlin("1.1")
public val isAbstract: Boolean
//8.判断类是否为密封类,密封类:用sealed修饰,其子类只能在其内部定义
@SinceKotlin("1.1")
public val isSealed: Boolean
//9.判断类是否为data类
@SinceKotlin("1.1")
public val isData: Boolean
//10.判断类是否为成员类
@SinceKotlin("1.1")
public val isInner: Boolean
//11.判断类是否为companion object
@SinceKotlin("1.1")
public val isCompanion: Boolean
//12.返回类中定义的其他类,包括内部类(inner class声明的)和嵌套类(class声明的)
public val nestedClasses: Collection<KClass<*>>
 //13.判断一个对象是否为此类的实例
@SinceKotlin("1.1")
public fun isInstance(value: Any?): Boolean
//14.返回这个类的泛型列表
@SinceKotlin("1.1")
public val typeParameters: List<KTypeParameter>
//15.类其直接基类的列表
@SinceKotlin("1.1")
public val supertypes: List<KType>
//16.返回类所有的基类
val KClass<*>.allSuperclasses: Collection<KClass<*>>
//17.返回类的伴生对象companionObject
val KClass<*>.companionObject: KClass<*>?

使用Kotin中反射注意的问题

在Kotlin1.1中如果反射String,Map,List等类型时,会抛出一个built-in Kotlin Types的异常,这是因为在Kotlin1.1版本中还没有对这些类型添加支持,在Kotlin1.2版本中,这个问题已经解决。

Kotlin关于反射的内容都放在kotlin-reflect的jar包中,这个jar包有2.6M,对于移动端开发,需要占用一定的内存空间。

最后就是关于Kotlin反射的效率问题,在Java中反射大概需要几十微秒,在Kotlin就需要几百甚至上千微秒,如果是通过反射访问对象或构造属性,甚至需要上万微秒,对此,官方给出的解释是,现在还没有精力进行优化,相信后续的版本中,效率问题会有所改善。

参考链接

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • 利用lambda表达式树优化反射详解

    前言 本节重点不讲反射机制,而是讲lambda表达式树来替代反射中常用的获取属性和方法,来达到相同的效果但却比反射高效. 每个人都知道,用反射调用一个方法或者对属性执行SetValue和GetValue操作的时候都会比直接调用慢很多,这其中设计到CLR中内部的处理,不做深究.然而,我们在某些情况下又无法不使用反射,比如:在一个ORM框架中,你要将一个DataRow转化为一个对象,但你又不清楚该对象有什么属性,这时候你就需要写一个通用的泛型方法来处理,以下代码写得有点恶心,但不妨碍理解意思: //

  • 基于Java反射的map自动装配JavaBean工具类设计示例代码

    前言 JavaBean是一个特殊的java类,本文将给大家详细介绍关于基于Java反射的map自动装配JavaBean工具类设计的相关内容,下面话不多说了,来一起看看详细的介绍吧 方法如下 我们平时在用Myabtis时不是常常需要用map来传递参数,大体是如下的步骤: public List<Role> findRoles(Map<String,Object> param); <select id="dindRoles" parameterType=&qu

  • 实例讲解Java基础之反射

    前期准备 编写一个真实类phone,实现list接口 public class Phone implements List { public double price; public String name; public Phone() { } public Phone(double price, String name) { this.price = price; this.name = name; } public double getPrice() { return price; } p

  • Java反射机制的精髓讲解

    1,什么是反射? java的反射,允许程序在运行时,创建一个对象,获取一个类的所有相关信息等. 2,Class类 要了解反射,就绕不开Class类. 我们平时开发的类,例如ClassA,一般会有一些属性,会有几个构造方法,也会有一些普通方法,我们还可以使用ClassA来创建对象,例如ClassA classA = new ClassA(). java程序在运行时,其实是很多类的很多个对象之间的协作.jvm如何管理这些类呢?它如何知道各个类的名称,每个类都有哪些属性和哪些方法呢? jvm会给每个类

  • 详解Golang利用反射reflect动态调用方法

    编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 每种语言的反射模型都不同,并且有些语言根本不支持反射.Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的,只要包含这个包就可以使用. 多插一句,

  • 通过反射注解批量插入数据到DB的实现方法

    批量导入思路 最近遇到一个需要批量导入数据问题.后来考虑运用反射做成一个工具类,思路是首先定义注解接口,在bean类上加注解,运行时通过反射获取传入Bean的注解,自动生成需要插入DB的SQL,根据设置的参数值批量提交.不需要写具体的SQL,也没有DAO的实现,这样一来批量导入的实现就和具体的数据库表彻底解耦.实际批量执行的SQL如下: insert into company_candidate(company_id,user_id,card_id,facebook_id,type,create

  • Java高级特性之反射机制实例详解

    本文实例讲述了Java高级特性之反射机制.分享给大家供大家参考,具体如下: 老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值 一. 什么是反射? 二.反射能做什么? 一. 什么是反射? 用在Java身上指的是我们可以于运行时加载.探知.使用编译期间完全未知的classes.换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体.或对其fields设值.或唤起其methods. 如果你是一个

  • 实例讲解Java中动态代理和反射机制

    反射机制 Java语言提供的一种基础功能,通过反射,我们可以操作这个类或对象,比如获取这个类中的方法.属性和构造方法等. 动态代理:分为JDK动态代理.cglib动态代理(spring中的动态代理). 静态代理 预先(编译期间)确定了代理者与被代理者之间的关系,也就是说,若代理类在程序运行前就已经存在了,这种情况就叫静态代理 动态代理 代理类在程序运行时创建的代理方式.也就是说,代理类并不是在Java代码中定义的,而是在运行期间根据我们在Java代码中的"指示"动态生成的. 动态代理比

  • 使用反射机制控制Toast的显示时间

    本文为大家分享了使用反射机制控制Toast显示时间的具体代码,供大家参考,具体内容如下 1.Toast源码分析: Toast的默认view是在transient_notification.xml中定义的一个TextView,如果需要设置Toast的界面,可以通过setView方法实现:如果需要设置Toast默认显示的位置,可以通过setGravity或者setMargin方法进行设置,值得一提的是setMargin方法的参数范围是0-1即它是屏幕的百分比,如setMargin(0.1,0.1).

  • ES6 如何改变JS内置行为的代理与反射

    代理(Proxy)可以拦截并改变 JS 引擎的底层操作,如数据读取.属性定义.函数构造等一系列操作.ES6 通过对这些底层内置对象的代理陷阱和反射函数,让开发者能进一步接近 JS 引擎的能力. 一.代理与反射的基本概念 什么是代理和反射呢? 代理是用来替代另一个对象(target),JS 通过new Proxy()创建一个目标对象的代理,该代理与该目标对象表面上可以被当作同一个对象来对待. 当目标对象上的进行一些特定的底层操作时,代理允许你拦截这些操作并且覆写它,而这原本只是 JS 引擎的内部能

随机推荐