目錄
在運行時通過Class對象動態獲取類信息,並且可以操作類或對象的內部屬性。反射可以動態創建對象並調用其屬性。而這種動態獲取信息以及動態調用對象方法的功能就是JAVA的反射。
反射中常用到的有Class,Field,Method,Constructor這幾個類,這些類也是將類信息封裝成相應的類
Class類常用到的有方法有
Method對象最重要的方法就是invoke,Constructor最重要的方法是newInstance
下面是對反射中比較常用的一些方法的舉例
class MondayStudyReflect{
private String getup;
private String wash;
public String review;
public String getWash() {
return wash;
}
public void setWash(String wash) {
this.wash = wash;
}
public String getReview() {
return review;
}
public void setReview(String review) {
this.review = review;
}
private String getGetup() {
return getup;
}
private void setGetup(String getup) {
this.getup = getup;
}
public MondayStudyReflect(){
System.out.println("無參構造方法");
}
public MondayStudyReflect(String wash,String review){
System.out.println("無參構造方法 wash:"+wash+";review:"+review);
this.wash = wash;
this.review = review;
}
public void study(String message){
System.out.println("公共有參方法調用:"+message);
}
private void summary() {
System.out.println("私有無參方法調用");
}
}
1.獲取Class對象的三種方式
@Test
public void getClassThreeMethod() throws Exception{
Class classOne = MondayStudyReflect.class;
MondayStudyReflect mondayStudyReflect = new MondayStudyReflect();
Class classTwo = mondayStudyReflect.getClass();
Class classThree = Class.forName("com.example.findwork.reflect.MondayStudyReflect");
if(classOne == classTwo && classTwo == classThree){
System.out.println("三種方法獲取的class對象是同一個");
//最後輸出結果
//三種方法獲取的class對象是同一個
}
}
一般都是通過調用Class的forName方法來獲取類的Class對象,因爲這個更加靈活,我們只需要獲取到類的全限定名稱就可以了
通過對象的getClass方法獲取的話,我們已經有這個類的實例了,所以也不太需要class對象了。
2.獲取類的相關屬性
/**
* 測試反射屬性的獲取
* @throws Exception
*/
@Test
public void testReferectFields()throws Exception{
Class classField = Class.forName("com.example.findwork.reflect.MondayStudyReflect");
Field[] fieldArr = classField.getFields();
System.out.println("獲取所有的公開的類屬性");
for(Field field:fieldArr){
System.out.println("屬性名:"+field.getName()+";屬性類型:"+field.getType());
}
Field[] fieldArrTwo = classField.getDeclaredFields();
System.out.println("獲取所有的類屬性,包括私有屬性");
for(Field field:fieldArrTwo){
System.out.println("屬性名:"+field.getName()+";屬性類型:"+field.getType());
}
Field filedReview = classField.getField("review");
System.out.println("通過屬性名稱獲取公開屬性");
System.out.println("屬性名:"+filedReview.getName()+";屬性類型:"+filedReview.getType());
Field filedWash = classField.getDeclaredField("wash");
System.out.println("通過屬性名稱獲取私有屬性");
System.out.println("屬性名:"+filedWash.getName()+";屬性類型:"+filedWash.getType());
}
輸出結果
獲取所有的公開的類屬性
屬性名:review;屬性類型:class java.lang.String
獲取所有的類屬性,包括私有屬性
屬性名:getup;屬性類型:class java.lang.String
屬性名:wash;屬性類型:class java.lang.String
屬性名:review;屬性類型:class java.lang.String
通過屬性名稱獲取公開屬性
屬性名:review;屬性類型:class java.lang.String
通過屬性名稱獲取私有屬性
屬性名:wash;屬性類型:class java.lang.String
3.獲取類的公開方法和私有方法
/**
* 測試反射方法的運用
* @throws Exception
*/
@Test
public void testReflectMethod() throws Exception{
Class classMethod = Class.forName("com.example.findwork.reflect.MondayStudyReflect");
Method[] methodArr = classMethod.getMethods();
System.out.println("===========獲取所有的公開的類方法=========");
for(Method method:methodArr){
System.out.print("方法名:"+method.getName()+" ");
}
Object object = classMethod.newInstance();//其實是得到了MondayStudyReflect的實例,等同於 new MondayStudyReflect
Method methodSetWash = classMethod.getMethod("setWash",String.class);
methodSetWash.invoke(object,"調用公開方法");
Method methodGetWash = classMethod.getMethod("getWash");
String wash = methodGetWash.invoke(object).toString();
System.out.println("通過反射調用方法獲取到的參數 wash:"+wash);
//調用私有方法
Method methodSetGetup = classMethod.getDeclaredMethod("setGetup",String.class);
methodSetGetup.setAccessible(true);//表示可以調用,沒有設置這一步調用私有方法是會出現問題的
methodSetGetup.invoke(object,"調用私有方法");
Method methodgetGetup = classMethod.getDeclaredMethod("getGetup");
methodgetGetup.setAccessible(true);//表示可以調用,沒有設置這一步調用私有方法是會出現問題的
String getUp = methodgetGetup.invoke(object).toString().toString();
System.out.println("通過反射調用方法獲取到的參數 getUp:"+getUp);
}
輸出結果
===========獲取所有的公開的類方法=========
方法名:setWash 方法名:getWash 方法名:getReview 方法名:setReview 方法名:study 方法名:wait 方法名:wait 方法名:wait 方法名:equals 方法名:toString 方法名:hashCode 方法名:getClass 方法名:notify 方法名:notifyAll 無參構造方法
通過反射調用方法獲取到的參數 wash:調用公開方法
通過反射調用方法獲取到的參數 getUp:調用私有方法
可以看到獲取公開所有方法的時候還會獲取父類Object公開的方法
4.獲取構造方法
/**
* 測試構造方法的運用
*/
@Test
public void testReflectConsttruct() throws Exception{
Class classMethod = Class.forName("com.example.findwork.reflect.MondayStudyReflect");
Constructor constructor = classMethod.getDeclaredConstructor();
constructor.setAccessible(true);
MondayStudyReflect nondayStudyReflect = (MondayStudyReflect)constructor.newInstance();
Constructor constructorOne = classMethod.getConstructor(String.class,String.class);
MondayStudyReflect nondayStudyReflectTwo = (MondayStudyReflect)constructorOne.newInstance("aaa","bbb");
}
輸出結果
無參構造方法
無參構造方法 wash:aaa;review:bbb
5.反射的好處和壞處
好處:
1.解耦類與類之間的關係,讓類的調用更加靈活,向IOC的基本原理就是反射
壞處
1.調用性能沒有直接調用好
2.破壞了類的封裝性,可以調用私有方法和屬性,最典型的就是破壞了單例模式