反射
之前我們學到的是封裝,而反射其實就是反封裝的過程(解封)
引入:
首先我們知道,Java程序運行過程和編譯出來的class是兩套東西
我們可不可以只有類沒有對象?可以
之前那我們學習的對象都是依託於類而存在的
我們可不可以只有對象沒有類?可以。想一想io傳對象,別人創建好對象傳給你,你得到了這個對象的二進制字節,可以把這個變成一個對象而存在,只是沒有這個類型而已。
定義:
所謂反射就是指,在Java程序運行時,獲得其某些對象的實際結構與類型的過程
我們可以從類型裏面獲得:方法,方法的參數,成員變量等
如果想要知道這個對象真真正正歸於那個類
Human human1 = new Woman();
System.out.println(human1.getClass().getName());
獲取某個類型的對象(模板)
類型的對象並不是說這個類型實例化一個對象出來,而是這個類型對象裏面包括了描述這個類所有的特徵(方法、屬性)
首先理解類型也是一個類,其中類型也能創建對象
對象 = Object 類型 = Class
-
已經有了對象,通過 對象.getClass方法獲取
Class c = human.getClass();
-
已經有了類型,通過 類型.class屬性獲取
Class m = Woman.class;
-
m和c裏面都包括了描述Woman裏的所有的動作(屬性、方法)m和c就是Woman的類模板
-
.class文件加載到內存中後,就變成了Class
Class類裏面的一些方法
-
getConstructors():獲得指向的類型的構造方法
-
getMethods():通過類型的對象拿到這個類型裏的方法**(獲得所有方法,但不能獲取私有的方法)**(通過getMethods獲得的方法是可以直接調用的,不需任何改動)
Method[] methods = c.getMethods();//獲得所有方法,不能獲取私有的方法 for (Method m : methods) { System.out.println(m.getName()); }
-
getDeclaredMethods():通過類型的對象拿到這個類型裏的方法**(獲得該類裏聲明的方法,私有公有的方法都可以獲得)**
-
getMethods(“方法名”,方法名的參數集):獲得單個方法,但是有參數
Method md = c.getMethod("foo",null);//md是c類型下的一個方法 Method md = c.getMethod("doo",int.class);
-
getParameters():獲得方法的所有參數
Method[] methods = c.getMethods(); for (Method m : methods) { System.out.print(m.getName() + "("); Parameter[] parameters = m.getParameters(); for(int i = 0; i < parameters.length; i++) { System.out.print(parameters[i].getType().getName()); if(i != parameters.length - 1) { System.out.print(","); } } System.out.println(")"); }
-
上面的兩個方法可以拿到方法名和他的參數,這樣就可以執行這個方法了。你可能會想有必要這麼麻煩嗎,之間去那個類裏面看一眼不就完了。這裏要告訴你,這個類你根本是看不到的!
-
getFields():獲得所有屬性
-
getField(“屬性名”):獲得某個屬性,要指定屬性名
-
set(Object obj, Object value):設置某個對象的屬性的值
-
get(Object obj):獲得某個對象的某個屬性的值
Class c = human.getClass(); Feild field = c.getField("age");//獲得類的名爲age的屬性放在field裏 field.get(human);//拿到human對象裏field存放的值 field.set(human,82);//相當於把human對象裏的age屬性的值改爲82
反射的🐂🍻之處:可以根據一個對象獲得類信息,也可以利用這個對象獲得類信息反過來創建新的對象,調用方法。
不用new的過程創建對象
方式一(newInstance()):
注:如果構造方法有參數,就不能用這種方式創建對象。這就需要通過反射調用有參的構造方法,然後再調用newInstance
Class c = Woman.class;//通過Woman獲得了一個Class對象
Object obj = c.newInstance(); //獲得c類型的對象(Woman類型)
Class c = Woman.class;
Constructor constructor = c.getConstructor(int.class, int.class, String.class);
Object o = constructor.newInstance(1,2,"zaq");
方式二:
- forName(String name):創建對象,參數name必須是類的類全名(通過這種方式創建對象的前提是,這個類必須在你的項目中存在)
Class c = Woman.class;
Object obj = Class.forName(c.getName());
Object obj = Class.forName("com.home.java.Woman");
Method類裏的一些方法
- invoke(Object obj, Object… args):用某個對象obj執行某個方法(這個對象中一定要有這個方法)(通過反射調用對象的方法)
Class c = human.getClass();
Object obj = c.newInstance(); //obj是c類型的對象
Method md = c.getMethod("doo",int.class,String.class);//md是c類型下的一個方法
md.invoke(obj,56,"aaa");//obj來執行md獲得的doo方法 等同於:obj.doo(56,"aaa");
md.invoke(human,56,"aaa");//通過反射調用對象的方法,等同於:((Woman)human).doo(56,"aaa");
- setAccessible(true):設置可訪問私有屬性、方法。外掛呀!🙀
Method method1 = c.getDeclaredMethod("hahah");//hahah是一個私有方法
method1.setAccessible(true);//讓私有的方法可以被訪問,外掛
method1.invoke(o,null);
比如別人給你一個類,說這個類就工具類。我要是想知道這個類具體怎麼實現的,就可以用反射來做。(jdgui也可以)