反射
Reflection(反射)是 Java 程序開發語言的特徵之一,它允許運行中的 Java 程序對自身進行檢查,或者說“自審”,也有稱作“自省”。反射非常強大,它甚至能直接操作程序的私有屬性。我們前面學習都有一個概念,private的只能類內部訪問,外部是不行的,但這個規定被反射赤裸裸的打破了。
反射就像一面鏡子,它可以在運行時獲取一個類的所有信息,可以獲取到任何定義的信息(包括成員變量,成員方法,構造器等),並且可以操縱類的字段、方法、構造器等部分。
爲什麼需要反射:
好好的我們new User(); 不是很好,爲什麼要去通過反射創建對象呢?那我要問你個問題了,你爲什麼要去餐館喫飯呢?例如:我們要喫個牛排大餐,如果我們自己創建,就什麼都得管理。
好處是,每一步做什麼我都很清晰,壞處是什麼都得自己實現,那不是累死了。牛接生你管,喫什麼你管,屠宰你管,運輸你管,冷藏你管,烹飪你管,上桌你管。就拿做菜來說,你能有特級廚師做的好?
那怎麼辦呢?有句話說的好,專業的事情交給專業的人做,飼養交給農場主,屠宰交給劊子手,烹飪交給特級廚師。那我們幹嘛呢?
我們翹起二郎腿直接拿過來喫就好了。再者,飯店把東西做好,不能扔到地上,我們去撿着喫吧,那不是都成原始人了。那怎麼辦呢?很簡單,把做好的東西放在一個容器中吧,如把牛排放在盤子裏。
在開發的世界裏,spring就是專業的組織,它來幫我們創建對象,管理對象。我們不在new對象,而直接從spring提供的容器中beans獲取即可。Beans底層其實就是一個Map<String,Object>,最終通過getBean(“user”)來獲取。而這其中最核心的實現就是利用反射技術。
總結一句,類不是你創建的,是你同事或者直接是第三方公司,此時你要或得這個類的底層功能調用,就需要反射技術實現。有點抽象,彆着急,我們做個案例,你就立馬清晰。
反射Class類對象
- Class.forName(“類的全路徑”);
- 類名.class
- 對象.getClass();
常用方法
- 獲得包名、類名
- getPackage().getName()//包名
- getSimpleName()//類名
- getName()//完整類名
!!成員變量定義信息
- getFields()//獲得所有公開的成員變量,包括繼承的變量
- getDeclaredFields()//獲得本類定義的成員變量,包括私有,不包括繼承的變量
- getField(變量名)
- getDeclaredField(變量名)
!!構造方法定義信息
- getConstructor(參數類型列表)//獲得公開的構造方法
- getConstructors()//獲得所有公開的構造方法
- getDeclaredConstructors()//獲得所有構造方法,包括私有
- getDeclaredConstructor(int.class, String.class)
方法定義信息
- getMethods()//獲得所有可見的方法,包括繼承的方法
- getMethod(方法名,參數類型列表)
- getDeclaredMethods()//獲得本類定義的方法,包括私有,不包括繼承的方法
- getDeclaredMethod(方法名, int.class, String.class)
反射新建實例
- newInstance();//執行無參構造
- newInstance(6, “abc”);//執行有參構造
- getConstructor(int.class, String.class); //執行含參構造,獲取構造方法
反射調用成員變量
- getDeclaredField(變量名); //獲取變量
- setAccessible(true); //使私有成員允許訪問
- set(實例, 值); //爲指定實例的變量賦值,靜態變量,第一參數給 null
- get(實例); //訪問指定實例的變量的值,靜態變量,第一參數給 null
反射調用成員方法
- 獲取方法
- Method m = c.getDeclaredMethod(方法名, 參數類型列表);
- m.setAccessible(true) ;//使私有方法允許被調用
- m.invoke(實例, 參數數據) ;//讓指定的實例來執行該方法
反射的應用
創建類
class Student{
String name="jack";
int age=20;
public Student() {
System.out.println("無參構造");
}
public Student(String name) {
this.name=name;
System.out.println("含參構造"+name);
}
public void show(int a) {
System.out.println("show()..."+a);
}
}
獲取類對象
private static void method() throws Exception {
Class clazz = Student.class;
Class<?> clazz2 = Class.forName("seday15.Student");
Class clazz3 = new Student().getClass();
System.out.println(clazz.getName());
System.out.println(clazz2.getName());
System.out.println(clazz3.getName());
}
獲取構造方法
private static void method3(Class clazz) {
Constructor[] cs = clazz.getDeclaredConstructors();
for (Constructor c : cs) {
String name = clazz.getSimpleName();
System.out.println(name);
Class[] cs2 = c.getParameterTypes();//參數
System.out.println(Arrays.toString(cs2));
}
}
獲取成員方法
private static void method4(Class clazz) {
Method[] ms = clazz.getMethods();
for (Method m : ms) {
String name = m.getName();
System.out.println(name);
Class<?>[] cs = m.getParameterTypes();
System.out.println(Arrays.toString(cs));
}
}
獲取成員變量
private static void method2(Class clazz) {
Field[] fs = clazz.getFields();//獲取public的屬性
for (Field f : fs) {
String name = f.getName();
String tname = f.getType().getSimpleName();
System.out.println(name);
System.out.println(tname);
}
}
我們再來說說暴力反射,什麼是暴力反射呢?Java中有許多的方法和對象爲了安全考慮,都被封裝在類中。通常這些私有的方法和對象都只能在該類的內部進行調用,對於外部的類來說,都是隱藏、不可見的。爲了能夠在外部類中獲取和操作這些私有的對象和方法,就可以使用暴力反射的方式來實現。簡單來講就是指可以將程序中的私有的屬性或者方法通過反射技術,暴力的獲取到資源。
創建Person類
class Person{
private String name="jack";
private int age = 30;
private void show(int[] a) {
System.out.println("show()..."+Arrays.toString(a));
}
private void test() {
System.out.println("test()...");
}
}
看以上這個例子,成員變量和成員方法都是私有的,那麼我們將如何獲取它的值呢?我們來測試一下
package seday16new;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectPerson {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("seday16new.Person");
// method(clazz);//隱私屬性
method2(clazz);//執行方法
}
private static void method2(Class<?> clazz) throws Exception {
Method m = clazz.getDeclaredMethod("show", int[].class);
Object obj = clazz.newInstance();
m.setAccessible(true);//方法隱私可見
m.invoke(obj, new int[]{1,2,3});//執行
}
private static void method(Class clazz) throws Exception {
Field f = clazz.getDeclaredField("name");
System.out.println(f.getType().getName());
f.setAccessible(true);//屬性隱私可見
Object obj = clazz.newInstance();
// f.set(obj, "rose");//設置值
System.out.println(f.get(obj));//獲取值
//---所有屬性
Field[] fs = clazz.getDeclaredFields();
for (Field ff : fs) {
System.out.println(ff);
ff.setAccessible(true);//暴力反射
System.out.println(ff.get(obj));
}
}
}
結果:
- 獲取私有屬性值並修改
- 獲取私有方法並執行