反射:
在運行狀態中,對於任意一個類都能知道這個類的所有屬性和方法,對於任意一個對象,都能夠調用任意一個方法和屬性。簡單來說就是:根據現有對象倒推類的組成
反射的作用:
反編譯過程:使得在運行時就可獲得class文件的信息
**
取得Class對象的三種方法:**
1.使用Object類的getClass():但要用這個類的實例來調用
2.類名.calss
3.使用Class類提供的forName(String className):傳入的名稱必須是類的全限定名
區別:
//這是我定義的一個類 裏面有靜態代碼塊
class Person{
private String name;
private int age;
public Person(){}
public void test(){
System.out.println("good");
}
//注意
static {
System.out.println("static port");
}
}
//使用getClass()
Person person = new Person();
Class<?> c = person.getClass();
//使用類名.class
Class<?> cl = Person.class;
//使用Class類的forName()
Class<?> cls = Class.forName("www.bite.reflect.Person");
通過運行程序可先看到一個現象
只有使用類名.class這種方法獲取類的class對象時沒有加載靜態代碼塊,這說明此時並沒有加載類,但是使用Object類的getClass()方法需要用該類的實例來調用,這時已經有該類的實例了,而使用forname()這種方法既不需要實例對象,又加載了類。
通過反射取得實例化對象:
public T newInstance()
throws InstantiationException, IllegalAccessException
通過class對象調用newInstance()方法取得該類的實例化對象
通過這種方法取得類的實例是應該在類中保留一個無參構造(還有一種用構造方法調用newInstance()取得類實例的方法在下面詳細說明)
應用:反射實現工廠模式,達到具體子類增加也不需要修改工廠類的代碼
核心代碼 以後再對工廠模式進行總結
反射與類操作:
通過反射取得父類信息:
1.取得包信息:
public Package getPackage()
2.取得父類的Class對象:
public native Class<? super T> getSuperclass();
3.取得所有實現的父接口:
public Class<?>[] getInterfaces()
反射調用構造:
1.取得指定參數的構造:
//getConstructor()方法只能取得public權限的
Constructor<?> con = cls.getConstructor(int.class,String.class);
getDeclaredConstructor(參數)——與權限無關
2.取得所有構造:
//僅限於public權限
Constructor<?>[] cons = cls.getConstructors();
getDeclaredConstructors()——與權限無關
使用Constructor類的newInstance():
//取得指定構造方法
Constructor<?> con = cls.getConstructor(int.class,String.class);
//通過給newInstance()方法傳指定格式單位參數實例化類對象
System.out.println(con.newInstance(21,"liyifeng"));
如果取得的構造函數是private權限的話,可以通過構造函數的對象設置setAccessible(true)動態破壞封裝,盡在本次JVM金正中有效。
反射調用普通方法:
1.取得全部普通方法:
getMethods();
2.取得指定普通方法:
getMethod(方法名,方法參數類型)
調用方法的支持:invoke(實例對象,調用的參數)——我理解爲利用反射拿到方法的對象後利用invoke去調用這個方法
例如:
Liyifeng liyifeng = (Liyifeng) cls.newInstance();
//得到指定方法的對象
Method setNameMethod = cls.getMethod("setName", String.class);
//invoke是一個調用方法的支持
//invoke方法的參數:代調用方法的實例對象 方法需要傳入的參數
//實際這裏相當於liyifeng.setName("offila")
setNameMethod.invoke(liyifeng,"offila");//此時已經調用setName方法修改了名字
Method getNameMethod = cls.getMethod("getName");
System.out.println(getNameMethod.invoke(liyifeng));
反射調用類中屬性:
類中的所有屬性都在類對象實例化之後纔會分配空間,所以此時要想調用類的屬性,就要先拿到類的實例化對象。
1.取得類中所有屬性:
getFields()——父類
getDeclaredFields()——子類
2.取得類中指定屬性
getField(屬性名)——父類
getDeclaredField(屬性名)——子類
在取得父類屬性時有權限限制,只能取得父類public權限的屬性,本類屬性沒有限制
File類中的方法:
set(實例對象,要設置的值)
get(實例對象)
getType()
方法的使用
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
Class<?> cls = Class.forName("www.bite.reflect.B");
Object object = cls.newInstance();
Field field = cls.getDeclaredField("school");
field.setAccessible(true);
field.set(object,"XUST");
System.out.println(field.get(object));
System.out.println(field.getType().getName());//得到類的全限定名
System.out.println(field.getType().getSimpleName());//得到類名
}