写在前面:
反射技术在框架开发中举足轻重,可以说是框架设计的灵魂,现在市面上绝大部分的框架都用到了反射机制,其在程序的运行过程中,动态操作对象,解耦程序,提高程序扩展性,使得反射机制成为框架设计领域的神器,反射机制也是java进阶必不可少的知识。
下面是对java反射基础语法的学习和使用:
一、获取对象类型:
val name = "aaa"
val clazz = name.javaClass
print(clazz)
上面代码定义了一个字符串name
,通过调用javaClass
获取它的类型(java中调用getClass()
方法),运行结果如下:
当然了,这里定义的一个字符串,不用运行,我们也知道类型是String类型,这里只是举个简单的例子,由此我们可以延申,在日常开发中我们可以通过javaClass
获取这个对象的类型。
二、获取对象构造方法:
为了便于测试,我定义了一个类:
class Test(name: String,age: Int){
private val sex: String? = null
constructor(name: String) : this(name,0){
"my name is $name".p("public constructor:")
}
private constructor(age: Int) : this("",age){
"i am $age years old".p("private constructor:")
}
private fun introduce(name: String,age: Int){
"my name is $name and i am $age years old".p("private method:")
}
}
其中重写了两个构造方法,一个公有的,一个私有的,还定义了一个私有方法和一个私有变量,后面会用到。.p()
方法是一个打印扩展方法,如下:
fun Any.p(tag: String){
println("$tag -----> $this")
}
回到正题,先把获取对象构造方法类型以及参数类型的代码贴上,跟着代码讲:
val test = Test("")
//获取test对象类型
val c2 = test.javaClass
c2.p("222")
//获取所有构造方法
val constructors = c2.declaredConstructors
constructors.forEach {
//获取构造参数类型
Modifier.toString(it.modifiers).p("构造函数类型:")
val paramterTypes = it.parameterTypes
//获取每个构造参数的每个参数类型
paramterTypes.forEach { clazz ->
"${clazz.name} ".p("参数类型:")
}
"**********".p("")
}
这里直接new了一个Test对象是为了方便测试,在实际开发中可能是通过调用某个方法获得一个对象。接着通过javaClass
获取对象类型,拿到对象类型后,通过declaredConstructors
获取这个对象所有的构造方法,每个构造方法再通过modifiers
可以获得当前构造方法的类型,是public还是private或者是protect就通过这个方法获取。通过parameterTypes
可以获取构造参数类型。运行上述代码结果如下:
第一行打印结果是new对象的时候调用了Test类的第一个构造方法生成的,第二行是test对象类型,后面是对每个构造方法的遍历打印,一共有三个构造方法,而类中我们只定义了两个,那是因为kotlin中直接将参数跟在类名后面会自动生成一个带所有参数的构造方法。通过对比代码和运行结果,也能验证通过declaredConstructors
获取构造方法类型和parameterTypes
获取构造参数类型的可行性。
上面是通过declaredConstructors
获取所有的构造参数,除此之外还可以通过getDeclaredConstructor(Class<?> parameterTypes)
获取特定的构造方法,传入你想要获取的那个构造放的构造参数类型,就可以获得相应的构造方法类型,比如想要获取Test类中定义的私有构造方法,代码如下:
val intConstructor = c2.getDeclaredConstructor(Int::class.java)
Modifier.toString(intConstructor.modifiers).p("constructor:")
打印结果:
获取特定的构造参数类型走到这一步,在日常工作中貌似获取构造方法也没什么用,别急,获取构造方法在下一步中会用到。
三、获取对象实例:
上一步,我们通过declaredConstructors
可以获取所有的构造方法,还可以通过getDeclaredConstructor(Class<?> parameterTypes)
获取特定的构造方法,这一步我们通过特定的构造方法,获取对象实例,下面是获取实例的代码:
val stringConstructor = c2.getDeclaredConstructor(String::class.java)
stringConstructor.newInstance("张三")
val intConstructor = c2.getDeclaredConstructor(Int::class.java)
//私有构造方法需要设置这一步
intConstructor.isAccessible = true
intConstructor.newInstance(25)
获取到的构造方法通过newInstance(Object ... initargs)
方法获得对象实例,传入的值就是构造参数值。这里需要注意的是,私有构造方法需要设置isAccessible = true
才可以。下面看下打印结果:
四、调用私有方法:
上面是获取构造方法的过程,这一步我们通过对象类型获取类中的私有方法,干货来了。
val method = c2.getDeclaredMethod("introduce",String::class.java,Int::class.java)
method.isAccessible = true
method.invoke(test,"李四",26)
通过getDeclaredMethod(String name, Class<?>... parameterTypes)
获取私有方法,第一个参数是你想要获取的方法名,后面传入调用这个方法需要的参数类型。由于是私有方法,所以需要设置isAccessible = true
。最后通过invoke()
方法传入反射的对象,第一个参数这里直接传入new出来的test对象,在实际开发中可用newInstance()获得的实例,后面的参数就是私有方法的传参。参数等就实现了私有方法的调用。下面是运行结果:
五、调用私有变量:
私有方法的调用攻破了,私有变量自然跑不掉,下面是设置私有变量值的代码:
val declaredField = c2.getDeclaredField("sex")
declaredField.isAccessible = true
declaredField.set(test,"女")
declaredField.get(test).p("sex:")
通过getDeclaredField(String name)
传入变量名获取私有变量,私有属性需要设置isAccessible = true
,之后通过set(Object obj, Object value)
设置变量值,第一个参数是反射的对象,第二个参数就是你要设置的值,最后可以通过get(Object obj)
方法获取私有变量值。看下运行结果:
以上五步就是对java反射基础语法的一个学习和简单运用,从第一步到第五步基本是环环相扣的。下面总结一下:
1、通过javaClass获取对象类型;
2、通过对象类型调用getDeclaredConstructor()获取特定的构造方法;
3、通过构造方法调用newInstance()可以获得对象实例;
4、通过对象类型调用getDeclaredMethod()获取私有方法,将获取到的实例传入invoke()方法可以完成对私有方法的调用;
5、调用getDeclaredField()获取私有变量,将获取到的实例传入可以完成对私有变量值的设置。
以上就是对反射技术的一个学习总结,谢谢阅读。
网友评论