關於Java中反射問題的權威解答,歡迎查閱!
阿新 • • 發佈:2018-11-01
1.反射介紹
- 在執行階段,動態獲取類的資訊和呼叫類的屬性和方法的機制稱為反射機制
2.反射的作用
- 獲取物件所屬的類(父類,介面)
- 通過類建立物件
- 獲取物件所有的屬性和方法(呼叫)
- 建立代理物件
3.反射採用api(java.lang.reflect)
- Class:包含類中所有的資訊
- 通過類載入器在載入過程中為每一個類建立唯一的class物件。
- Class建立的三種方式
//1.類名.class Class clz = Apple.class; //2.物件.getClass() Class clz2 = apple.getClass(); //3.類的全限定名稱(全路徑) try { Class clz3 = Class.forName("test.Apple"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
- 建立物件方式
/**
* 1.呼叫無參構造(若沒有無參構造,或無參構造沒有訪問許可權則建立失敗)
* 2.介面,抽象類,陣列,基本型別建立失敗
*/
Apple apple = (Apple) clz.newInstance();
apple.eat();
- Field: 封裝了屬性物件
//獲取屬性 //獲取封裝指定public屬性的field物件 Field field = clz.getField("weight"); //System.out.println(field); //給屬性賦值 apple.setWeight(12); //物件 值 Apple apple = clz.newInstance(); field.set(apple, 12); //獲取屬性的值 System.out.println(field.get(apple)); //獲取所有的public修飾的屬性(獲取父類的屬性) /*Field [] fields = clz.getFields(); System.out.println(Arrays.toString(fields));*/ //獲取所有的屬性(包含私有的,不能獲取父類) Field [] fields = clz.getDeclaredFields(); System.out.println(Arrays.toString(fields)); //獲取指定屬性(私有的) Field f = clz.getDeclaredField("size"); f.setAccessible(true); f.set(apple, 11); System.out.println(f.get(apple));
- Method: 封裝方法的物件
//1.獲取public修飾的指定方法
//Method method = clz.getMethod("show2");
Method method2 = clz.getMethod("show", String.class);
//執行方法的呼叫
method2.invoke(apple, "aaaa");
//2.獲取所有的public方法(父類的)
//clz.getMethods();
//3.獲取所有的方法(私有)
//clz.getDeclaredMethods();
//4.獲取指定私有方法
Method method = clz.getDeclaredMethod("show2");
method.setAccessible(true);
method.invoke(apple);
- Constructor: 包含了構造方法的資訊(class獲取)
GetConstructor(Class…paramerType):獲取公共的構造方法
GetConstructors():獲取公共的所有的構造方法
getDeclaredConstructor(Class…paramerType):該類所有構造方法之一(包含私有的)
getDeclaredConstructors():獲取所有的構造方法
//2.獲取有參構造
//獲取帶有一個String型別引數的構造方法
Constructor<Apple> constructor = clz.getConstructor(String.class);
//通過constructor建立物件
Apple apple = constructor.newInstance("紅色");
//apple.show();
/*Constructor<Apple> constructor = clz.getConstructor();//無參構造
Apple apple = constructor.newInstance();
System.out.println(apple);*/
//獲取所有的public構造方法
/*Constructor[] constructors = clz.getConstructors();
System.out.println(Arrays.toString(constructors));*/
//獲取所有的構造方法(包含私有的)
/*Constructor<?>[] declaredConstructors = clz.getDeclaredConstructors();
System.out.println(Arrays.toString(declaredConstructors));*/
//獲取指定構造方法
Constructor<Apple> constructor2 = clz.getDeclaredConstructor(int.class);
//授權
constructor2.setAccessible(true);
Apple apple2 = constructor2.newInstance(1);
apple2.show();
- 反射的優點和缺點
- 優點: 靈活性和擴充套件性,降低了耦合性
- 缺點: 維護難度大
- 代理模式
- 開閉原則: 面向修改關閉,面向擴充套件開放。
- 代理模式: java語言23種設計模式。(GOF的<<設計模式>>)
- 設計模式: 經驗,程式碼的擴充套件,鬆耦合。
- 訪問物件另一種方式。給需要操作的真實物件建立代理物件,通過操作代理物件實現對真實物件的使用,可以實現對真實物件內容擴充套件。
- 靜態代理: 在編譯期間,為每一個真實物件的類建立代理類
- 每一個真實物件的方法都要新增增強。
interface Yulequan{
void play();
void kongfu();
}
class LiYiFeng implements Yulequan{
@Override
public void play() {
System.out.println("我不會play");
}
@Override
public void kongfu() {
System.out.println("我不會kongfu");
}
}
//真實物件類
class BaoQiang implements Yulequan{
@Override
public void play() {
System.out.println("我會play");
}
@Override
public void kongfu() {
System.out.println("我會kongfu");
}
}
//代理類
class SongZhe implements Yulequan{
Yulequan bq;
public SongZhe(Yulequan bq) {
this.bq = bq;
}
@Override
public void play() {
System.out.println("開始");
bq.play();
System.out.println("結束");
}
@Override
public void kongfu() {
System.out.println("開始");
bq.kongfu();
System.out.println("結束");
}
}
public class StaticProxy {
public static void main(String[] args) {
Yulequan yl = new SongZhe(new LiYiFeng());
yl.kongfu();
}
}
- 動態代理:執行期間,為真實物件建立代理物件的方式。(反射)
- JDK的動態代理(介面+真正物件的類)
//1.建立目標類物件
YuLeQuan yl = new BQ();
//2.給目標物件建立代理物件
//2.1 目標類物件實現同一個介面
//2.2 代理類物件中需要獲取每一個方法
/*引數: 1.類載入器(用於載入獲取class物件)
* 2.interfaces:獲取目標物件所有實現的介面(獲取所有方法)
* 3.invocationhandler:真正遍歷處理每一個需要增強方法地方
* invoke方法: 訪問一次interface的方法,該方法就呼叫一次
* */
YuLeQuan proxy = (YuLeQuan) Proxy.newProxyInstance(
yl.getClass().getClassLoader(),
yl.getClass().getInterfaces(),
new InvocationHandler() {
//proxy:代理
//method:封裝了每一個遍歷的方法
//args:方法引數
//object 返回值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("開始");
//呼叫方法並返回
Object obj = method.invoke(yl, args);
System.out.println("結束");
return obj;
}
});
//3.呼叫代理物件方法
proxy.play();
proxy.kongfu();
- Cglib的動態代理(目標類)
- 匯入jar(cglib.jar,asm.jar)
//1.建立目標類物件
Lyf lyf = new Lyf();
//2.建立代理物件
Enhancer enhancer = new Enhancer();
//2.1 說明父子關係
enhancer.setSuperclass(Lyf.class);
//2.2 方法怎麼處理(回撥機制) 攔截每一個方法然後新增增強
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("開始");
Object obj = method.invoke(lyf, args);
System.out.println("結束");
return obj;
}
});
Lyf ly = (Lyf) enhancer.create();
//3.呼叫方法
ly.play();