標籤:java 反射
反射:
動態擷取位元組碼檔案對象(Person.class),並對其成員進行運行。
動態擷取位元組碼檔案對象的方式:
1:任何一個對象都是由位元組碼檔案對象建立的,所以任何一個對象都可以得到自己的位元組碼檔案對象
那麼這個功能應該定義在Object中,所以使用 getClass()
需要先new對象
2:每種資料類型都有一個 靜態class 屬性,通過該屬性可以得到位元組碼檔案對象 不需要new對象,但是需要Person類存在 3:Class類提供了一個靜態forName(String str)方法 只需要提供字串形式的包名+類名
1.Person person1 = new Person();//先載入Person.class到方法區Class<? extends Person> claz1 = person1.getClass();//得到了Person.classPerson person2 = new Person();Class<? extends Person> claz2 = person2.getClass();//得到了 Person.classSystem.out.println(claz1==claz2);//true ---->位元組碼檔案只載入一次到方法區,所以兩次得到的是同一個2.Class<Person> claz1 = Person.class;3.Class<?> claz1 = Class.forName("com.reflect.Person");
動態擷取位元組碼檔案對象,並建立對象:
1)調用無參構造方法建立對象
//當無參的構造方法不存在時,會發生InstantiationException //當構造方法的許可權過低時,會發生IllegalAccessException public static void createObj1() throws ClassNotFoundException, InstantiationException, IllegalAccessException { //Person person = new Person(); //擷取位元組碼檔案對象---Person.class Class<?> claz = Class.forName("com.reflect.Person"); //使用Class提供的newInstance()方法建立Person類型的對象 Object obj = claz.newInstance();//使用無參的構造方法建立對象 Person person = (Person)obj; System.out.println(person);}
2)使用有參數的構造方法建立對象
public static void createObj2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //Person person = new Person("小紅",20); //擷取位元組碼檔案對象---Person.class Class<?> claz = Class.forName("com.reflect.Person"); //得到構造方法所屬的Constructor類型的對象 Constructor<?> constructor = claz.getConstructor(String.class,int.class); //使用構造方法建立對象--使用Constructor提供的建立對象的功能 Person person =(Person)constructor.newInstance("小紅",20); System.out.println(person);}
3)動態建立對象並給屬性賦值
Class<?> claz = Class.forName("com.reflect.Person"); //得到屬性name所屬的 Field類型的對象//Field field = claz.getField("name");//只能擷取許可權是public 的屬性//System.out.println(field);//NoSuchFieldExceptionField field = claz.getDeclaredField("name");//因為name是非靜態屬性,所以必須通過對象訪問,所以先建立對象Object obj = claz.newInstance();//設定name屬性為可訪問的field.setAccessible(true);// 該方法是從父類中繼承的//使用Field類提供的賦值功能,給屬性賦值field.set(obj, "小紅");System.out.println(obj);
4)調用靜態方法
public static void method3() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //擷取位元組碼檔案對象---Person.class Class<?> claz = Class.forName("com.reflect.Person"); ///擷取被調用的方法所屬的 Method類型的對象 Method method = claz.getMethod("function", null); //執行方法 method.invoke(null, null);}
5)通過對象調用無參方法
public static void method1() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // Person person = new Person();person.show(); //擷取位元組碼檔案對象---Person.class Class<?> claz = Class.forName("com.reflect.Person"); //擷取被調用的方法所屬的 Method類型的對象 Method method = claz.getMethod("show", null); //show()屬於非靜態方式,需要對象去調用 Object obj = claz.newInstance(); //執行方法 method.invoke(obj, null);}
6)通過對象調用有參方法
//調用帶參的方法public static void method2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ //擷取位元組碼檔案對象---Person.class Class<?> claz = Class.forName("com.reflect.Person"); //擷取被調用的方法所屬的 Method類型的對象 Method method = claz.getMethod("fun", String.class); //fun()屬於非靜態方式,需要對象去調用 Object obj = claz.newInstance(); //執行方法 method.invoke(obj, "hello");}
反射應用:
這裡有一台筆記本,剛開始只有外設滑鼠。後來增加鍵盤、網路攝影機等等。
筆記本有running方法和use方法.外設都有open和close方法
public class NoteBook { public void runing(){ System.out.println("電腦運行"); } public void useKeyBoard(KeyBoard kb){ if(kb!=null){ kb.open(); kb.close(); } }}調用:NoteBook noteBook = new NoteBook();noteBook.runing();KeyBoard keyBoard = new KeyBoard ();noteBook.use(keyBoard );
如果添加外設滑鼠呢?
NoteBook又得添加一個useMouse(Mouse mouse){..}方法,如果再添加外設的話,還得添加相應的方法。
當然,這裡很容易解決,定義一個借口Usb.
interface Usb { public void open(); public void close();}
然後讓外設去實現這個介面,
在NoteBook裡面只用定義一個
useUsb(Usb usb){ usb.open(); usb.close();}在主程裡調用:Usb keyBoard = new KeyBoard ();noteBook.useUsb(keyBoard );Usb mouse = new Mouse();noteBook.useUsb(mouse);
如果還要添加外設,只用添加相應的類並實現Usb介面即可,那麼問題來了,主程式裡面又得new新的對象,調用相同的語句。
解決方案就可以用反射了:
1.把所有的外設添加到一個設定檔中
usb1=com.reflect.test.KeyBoard
usb2=com.reflect.test.Mouse
2.主程式裡調用
Properties properties = new Properties();FileInputStream fileInputStream = new FileInputStream("config\\config.properties");properties.load(fileInputStream); for(int i=1;i<=properties.size();i++){ String value properties.getProperty("usb"+i); Class<?> claz = Class.forName(value); Object obj = claz.newInstance(); Usb usb = (Usb)obj; noteBook.useUsb(usb);}
–>添加外設只用在設定檔中添加,主程式調用不用修改
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Java基礎筆記-反射及應用