前言
java反射機制指的是在java運行過程中,對于任意的類都可以知道他的所有屬性以及方法钮热,對于任意一個對象都可以任意的調(diào)用他的屬性和方法犁功,這種動態(tài)獲取對象信息和動態(tài)調(diào)用對象方法的功能稱為java反射機制,但是反射使用不當(dāng)會造成很高的成本腰根。
簡單實例
反射獲取類名稱
package top.crosssoverjie.study;
public class Reflect {
public static void main(String[] args) {
Class<Reflect> c1 = Reflect.class;
System.out.println(c1.getName());
Reflect r1 = new Reflect() ;
Class<Reflect> c2 = (Class<Reflect>) r1.getClass() ;
System.out.println(c2.getName());
try {
Class<Reflect> c3 = (Class<Reflect>) Class.forName("top.crosssoverjie.study.Reflect");
System.out.println(c3.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
輸出結(jié)果:
top.crosssoverjie.study.Reflect
top.crosssoverjie.study.Reflect
top.crosssoverjie.study.Reflect
以上的 c1,c2,c3是完全一樣的巢音,他們都有一個統(tǒng)一的名稱:叫做Reflect類的類類型。
反射的用處
獲取成員方法
public Method getDeclaredMethod(String name,Class<?>...parameterTypes)//得到該類的所有方法尽超,但是不包括父類的方法官撼。
public Method getMethod(String name,Class<?>...parameterTypes)//獲得該類的所有public方法,包括父類的似谁。
通過反射獲取成員方法調(diào)用的實例:
package top.crosssoverjie.study;
import java.lang.reflect.Method;
public class Person {
private String name="crossover" ;
private String msg ;
public Person(String name, String msg) {
this.name = name;
this.msg = msg;
System.out.println(name+"的描述是"+msg);
}
public Person() {
super();
}
public void say(String name ,String msg){
System.out.println(name+"說:"+msg);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public static void main(String[] args) {
try {
//首先獲取類類型
Class c1 = Class.forName("top.crosssoverjie.study.Person") ;
//通過newInstance()方法生成一個實例
Object o1 = c1.newInstance() ;
//獲取該類的say方法
Method m1 = c1.getMethod("say", String.class,String.class) ;
//通過invoke方法調(diào)用該方法
// m1.invoke(o1, "張三","你好啊") ;
Method[] methods = c1.getDeclaredMethods() ;
// for(Method m : methods){
// System.out.println(m.getName());
// }
Method[] methods2 = c1.getMethods() ;
for (Method method : methods2) {
System.out.println(method.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
輸出結(jié)果:
張三說:你好啊
所以我們只要知道類的全限定名就可以任意的調(diào)用里面的方法傲绣。
Method[] methods = c1.getDeclaredMethods() ;
for(Method m : methods){
System.out.println(m.getName());
}
輸出結(jié)果:
main
getName
setName
say
getMsg
setMsg
使用的還是之前那個Person類掠哥,所以這里只寫了關(guān)鍵代碼。這里輸出的是Person的所有public方法秃诵。
如果我們調(diào)用getMethods()
方法會是什么結(jié)果呢续搀?
Method[] methods2 = c1.getMethods() ;
for (Method method : methods2) {
System.out.println(method.getName());
}
輸出結(jié)果:
main
getName
setName
say
getMsg
setMsg
wait
wait
wait
hashCode
getClass
equals
toString
notify
notifyAll
這時我們會發(fā)現(xiàn)這里輸出的結(jié)果會比剛才多得多,這時因為getMethods()
方法返回的是包括父類的所有方法菠净。
獲取成員變量
我們還可以通過反射來獲取類包括父類的成員變量禁舷,主要方法如下:
public Field getDeclaredFiled(String name)//獲得該類所有的成員變量,但不包括父類的毅往。
public Filed getFiled(String name)//獲得該類的所有的public變量牵咙,包括其父類的。
還是按照之前例子中的Person類舉例攀唯,他具有兩個成員變量:
private String name="crossover" ;
private String msg ;
我們可以通過以下方法來獲取其中的成員變量:
Class c1 = Class.forName("top.crosssoverjie.study.Person") ;
Field field = c1.getDeclaredField("name");//獲取該類所有的成員屬性
通過以下例子可以獲取指定對象上此field的值:
package top.crosssoverjie.study;
import java.io.File;
import java.lang.reflect.Field;
public class Reflect {
public static void main(String[] args) {
try {
Class c1 = Class.forName("top.crosssoverjie.study.Person");
Field field = c1.getDeclaredField("name") ;
Object o1 = c1.newInstance() ;
/**
* 由于Person類中的name變量是private修飾的洁桌,
* 所以需要手動開啟允許訪問,是public修飾的就不需要設(shè)置了
*/
field.setAccessible(true);
Object name = field.get(o1) ;
System.out.println(name);
} catch (Exception e) {
e.printStackTrace() ;
}
// Class<Reflect> c1 = Reflect.class;
// System.out.println(c1.getName());
//
// Reflect r1 = new Reflect() ;
// Class<Reflect> c2 = (Class<Reflect>) r1.getClass() ;
// System.out.println(c2.getName());
//
// try {
// Class<Reflect> c3 = (Class<Reflect>) Class.forName("top.crosssoverjie.study.Reflect");
// System.out.println(c3.getName());
// } catch (ClassNotFoundException e) {
// e.printStackTrace();
// }
}
}
輸出結(jié)果:
crossover
我們也可以通過方法getDeclaredFieds()
方法來獲取所有的成員變量侯嘀,返回是是一個Field[]
數(shù)組另凌,只需要遍歷這個數(shù)組即可獲所有的成員變量。例子如下:
Field[] fields = c1.getDeclaredFields() ;
for(Field f :fields){
System.out.println(f.getName());
}
輸出結(jié)果如下:
name
msg
獲取構(gòu)造方法
可以通過以下兩個方法來獲取構(gòu)造方法:
public Constructor getDeclaredConstructor(Class<?>...parameterTypes)//獲取該類的所有構(gòu)造方法戒幔,不包括父類的吠谢。
public Constructor getConstructor(Class<?>...parameterTypes)//獲取該類的所有public修飾的構(gòu)造方法,包括父類的溪食。
在之前的Person類中有以下的構(gòu)造方法:
public Person(String name, String msg) {
this.name = name;
this.msg = msg;
}
我們可以通過以下方法來獲取Person類的構(gòu)造方法:
Constructor dc1 = c1.getDeclaredConstructor(String.class,String.class) ;
具體代碼如下:
Constructor dc1 = c1.getDeclaredConstructor(String.class,String.class) ;
dc1.setAccessible(true);
dc1.newInstance("小明","很帥") ;
dc1.newInstance("小明","很帥");
方法調(diào)用了Person類中的:
public Person(String name, String msg) {
this.name = name;
this.msg = msg;
System.out.println(name+"的描述是"+msg);
}
這個構(gòu)造方法囊卜,如果不傳參數(shù)的話,那么調(diào)用的就是無參的構(gòu)造方法错沃。輸出結(jié)果為:
小明的描述是很帥
通過反射了解集合泛型的本質(zhì)
通過以下例子程序可以看出:
package top.crosssoverjie.study;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class GenericEssence {
public static void main(String[] args) {
//聲明兩個list栅组,一個有泛型,一個沒有泛型
List list1 = new ArrayList() ;
List<String> list2 = new ArrayList<String>() ;
list2.add("你好") ;
// list2.add(11) ;加上泛型之后在編譯期間只能添加String枢析,不然會報錯玉掸。
System.out.println("list2的長度是:"+list2.size());
Class c1 = list1.getClass();
Class c2 = list2.getClass() ;
System.out.print("c1,c2是否相等:");
System.out.println(c1==c2);
try {
//通過反射繞過編譯器動態(tài)調(diào)用add方法,可能否加入非String類型的元素
Method method = c2.getDeclaredMethod("add", Object.class) ;
method.invoke(list2, 123) ;//在這里加入int類型醒叁,在上面如果加入int會出現(xiàn)編譯報錯司浪。
//list2的長度增加了,說明添加成功了
System.out.println("現(xiàn)在list2的長度是:"+list2.size());
/**
* 所以可以看出把沼,泛型只是在編譯期間起作用啊易,在經(jīng)過編譯進(jìn)入運行期間是不起作用的。
* 就算是不是泛型要求的類型也是可以插入的饮睬。
*/
} catch (Exception e) {
e.printStackTrace() ;
}
}
}
所以可以看出租谈,泛型只是在編譯期間起作用,在經(jīng)過編譯進(jìn)入運行期間是不起作用的捆愁。就算是不是泛型要求的類型也是可以插入的割去。
反射知識點
總結(jié)
泛型的應(yīng)用比較多:
- spring的IOC/DI窟却。
- JDBC中的中的加載驅(qū)動
參考
個人博客地址:http://crossoverjie.top。
GitHub地址:https://github.com/crossoverJie呻逆。