Class對(duì)象:
Class對(duì)象是將class文件文件讀入內(nèi)存,并為之創(chuàng)建一個(gè)Class對(duì)象找御。類加載器首先會(huì)檢查這個(gè)類的Class對(duì)象是否已被加載過(guò),如果尚未加載,默認(rèn)的類加載器就會(huì)根據(jù)類名查找對(duì)應(yīng)的.class文件泌参。獲取Class對(duì)象的有三種方式:(1)直接通過(guò)對(duì)象來(lái)獲取常空;(2)通過(guò)Class.forName來(lái)獲裙烈弧;(3)通過(guò)類直接獲取窟绷。經(jīng)常用到第二種方式锯玛,因?yàn)榈谝环N和第三種都需要導(dǎo)入這個(gè)Class對(duì)象的包才可以用。第二種方式則不需要兼蜈。代碼如下
(這里新建一個(gè)密碼類攘残,方便演示)
package com.example.kotlinstudy.reflect
class Password constructor(password: String) {
private var strName : String = ""
private var strPassword: String = password
private val strKey = "123456"
val type = "RSA"
constructor(password: String, name: String) : this(password){
strName = name
}
private fun getKey() : String{
println("getKey $type$strKey")
return type + strKey
}
override fun toString(): String {
return "$strName : $strPassword : $type"
}
}
三種方式
val password = Password("123")
// 直接通過(guò)對(duì)象來(lái)獲取(需要需要導(dǎo)入這個(gè)類的包为狸,并且有實(shí)例對(duì)象)
val clazz1 = password.javaClass
// 通過(guò)Class.forName來(lái)獲燃吖(需要知道類的路徑)
val clazz2 = Class.forName("com.example.kotlinstudy.reflect.Password")
// 通過(guò)類直接獲取(需要導(dǎo)入這個(gè)類的包)
val clazz3 = Password::class.java
反射的一些實(shí)際應(yīng)用:
- 修改類中私有屬性字段的值
我們現(xiàn)在獲取到一個(gè)Password對(duì)象辐棒,但是需要改變其私有變量strKey的值病曾,從聲明來(lái)看Password并未提供setter方法。這個(gè)時(shí)候漾根,反射就可以幫上忙
// 模擬獲取到一個(gè)Password類的實(shí)例
val password = Password("123")
// 直接通過(guò)對(duì)象來(lái)獲取
val clazz1 = password.javaClass
val field = clazz1.getDeclaredField("strKey")
field.isAccessible = true
field.set(password, "654312")
println(password)
輸出結(jié)果:
: 123 : RSA : 654312
備注:Class中有g(shù)etField(fieldname)方法只能獲取Public的字段Field泰涂。這里我們用getDeclaredField(fieldname)方法可以獲取所有的字段Field。
- 調(diào)用類中私有屬性的方法
// 模擬獲取到一個(gè)Password類的實(shí)例
val password = Password("123")
// 直接通過(guò)對(duì)象來(lái)獲取
val clazz1 = password.javaClass
val method = clazz1.getDeclaredMethod("getKey")
method.isAccessible = true
method.invoke(password)
輸出結(jié)果:
getKey RSA123456
調(diào)用setKey方法辐怕,反射帶參數(shù)的方法
// 模擬獲取到一個(gè)Password類的實(shí)例
val password = Password("123")
// 直接通過(guò)對(duì)象來(lái)獲取
val clazz1 = password.javaClass
val method = clazz1.getDeclaredMethod("setKey", String::class.java)
method.isAccessible = true
method.invoke(password, "111111")
輸出結(jié)果:
setKey : 111111
- 對(duì)過(guò)Class對(duì)象new一個(gè)實(shí)例
// 通過(guò)Class.forName來(lái)獲取
val clazz2 = Class.forName("com.example.kotlinstudy.reflect.Password")
var obj = clazz2.getConstructor(String::class.java).newInstance("147")
println(obj)
obj = clazz2.getConstructor(String::class.java, String::class.java).newInstance("147", "kotlin")
println(obj)
輸出結(jié)果:
: 147 : RSA : 123456
kotlin : 147 : RSA : 123456
知識(shí)梳理
Class對(duì)象的方法:
// 獲取所有公有方法
public Method[] getMethods()
// 獲取某個(gè)公有方法
public Method getMethod(methodname: String)
// 獲取所有的成員方法(包括私有)
public Method[] getDeclaredMehods()
// 獲取某個(gè)成員方法(包括私有)
public Method getDeclaredMehod(methodname: String)
// 獲取所有公有字段
public Field[] getFields()
// 獲取某個(gè)公有字段
public Field getField(fieldname: String)
// 獲取所有的字段(包括私有)
public Field[] getDeclaredFields()
// 獲取某個(gè)字段(包括私有)
public Field getDeclaredField(fieldname: String)
Field對(duì)象的方法:
// obj是Class對(duì)象的實(shí)例逼蒙,value是設(shè)置的值
field.set(obj: Object, value: Object)
Method對(duì)象的方法
// obj是Class對(duì)象的實(shí)例,agrs是對(duì)應(yīng)方法的參數(shù)
method.invoke(obj: Object, Object... args)