Java多態與反射



多態通過分離做什么和怎么做,從另一個角度將接口與實現分離開來;通過多態來消除類型之間的耦合關系,在Java中,多態也叫動態綁定,后期綁定或運行時綁定,那么什么是方法綁定?

方法調用綁定:

將一個方法與調用同一個方法的主體關聯起來被稱為綁定;若在程序執行前進行綁定(由編譯器和連接程序實現),叫做前期綁定;還有一種叫后期綁定,就是在運行時根據對象的類型進行綁定,也叫動態綁定或運行時綁定,也就是說,編譯器不知道對象的類型,但是方法調用機制能找到正確的方法體;在Java中除了static方法和final方法之外,所有的其他方法都是后期綁定;

因此,Java中所有的方法都是通過動態綁定來實現多態的,但如果直接訪問某個域,則這個訪問就會在編譯其進行解析;一般我們都通過將子類向上轉型為父類來實現多態,父類可以是抽象類,只要子類實現到父類的所有抽象方法,就可以將子類轉型為抽象的父類;Java里的抽象類本身是不能被實例化,但可以將子類的引用向上轉型為抽象的父類。
如:

abstract class Jack{
		public abstract void doSomething();
	}
class Product extends Jack{

		@Override
		public void doSomething() {
			System.out.println("Product");
			
		}
		
	}
	public static void main(String[] args) {
	//聲明一個抽象類Jack的變量,並指向其子類的實例化對象,合法的,Java的多態性會保證在運行時可以得到其正確的類型;
		Jack jack=new Product();
		//Jack jack=new Jack();//非法,不能實例化抽象類對象
		jack.doSomething();
	}

Java反射

Java反射機制是指在運行狀態時,可以知道任意一個類的的所有屬性和方法,對任意一個對象都可以調用它的任意一個方法;通過反射,可以在運行時實例化對象

Java反射提供的功能包括:

  • 在運行時判斷一個對象所屬的類;
  • 運行時構造任意一個類的對象;
  • 運行時判斷任意一個類的成員變量與方法;
  • 運行時調用任意一個對象的方法;
  • 生成動態代理;

我們想得到一個類的所有信息,第一步就是要得到類的Class對象,如果知道了一個對象或類的名字,就可以通過簡單的:
Class<?> clz=對象.getClass();
Class<?> clz=類的名字.class
得到,但如果在編譯期得不到具體類型,則可以通過Class.forName()來得到,但這個方法生成的結果在編譯時是不可知的,所有的方法特征簽名都是在運行時提取出來的。這是由Java的反射機制來提供足夠的支持。在得到這個類的Class對象后,我們就可以反射來構造對象,進而得到這個類的所有的信息。

 public static Class<?> forName(String className)
                throws ClassNotFoundException {
         Class<?> caller = Reflection.getCallerClass();
         return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

Java里的Class類與java.lang.reflect類庫一起對反射進行支持,該類庫包含了Field,Method,Constructor類(每個類都實現了Member接口),這些類型的對象是在JVM在運行時創建的,用以表示未知類里對應的成員。這樣我們就可以使用Constructor創建新的對象,用get(),set()方法修改與Field對象關聯的字段,用invoke()方法調用與Method對象關聯的方法。(摘自《Java編程思想》第四版)

下面簡要介紹利用反射實現的動態代理;

動態代理

步驟:

  • 新建委托類,實現動態代理要求委托類必須實現某個接口;
  • 新建中間類,用來連接代理類和委托類,這個中間必須實現InvocationHandler接口,這個接口只有一個invoke()方法;
  • 通過Proxy類新建代理類對象;

舉例:

interface Operate{
		void method1();
		void method2();
		void method3();
	}
	/**
	 * 委托類
	 * @author wood
	 *
	 */
	class Entrust implements Operate{

		@Override
		public void method1() {
			// TODO Auto-generated method stub
			System.out.println("*method1");
		}

		@Override
		public void method2() {
			// TODO Auto-generated method stub
			System.out.println("*method2");
		}

		@Override
		public void method3() {
			// TODO Auto-generated method stub
			System.out.println("*method3");
		}
		
	}
	/**
	 * 連接委托類與代理類的中間類;
	 * @author wood
	 *
	 */
	class DynamecProxyHandler implements InvocationHandler{
		private Object proxied;//委托類對象
		public DynamecProxyHandler(){
			
		}
		public DynamecProxyHandler(Object object){
			this.proxied=object;
		}
		@Override
		public Object invoke(Object proxy, Method method, Object[] arg2)
				throws Throwable {
			// TODO Auto-generated method stub
			Object object=method.invoke(proxied, arg2);
			System.out.println(method.getName());
			return object;
		}
		
	}
	//***********************
	DynamecProxyHandler dymaProxy=new DynamecProxyHandler(new Entrust());
		//通過Proxy類的靜態函數生成代理對象;
		Operate operate=(Operate)Proxy.newProxyInstance(Operate.class.getClassLoader(), new Class[]{Operate.class}, dymaProxy);
		operate.method1();
		operate.method2();
		operate.method3();

我們通過Procy.newProcyInstance函數新建了一個代理對象,實際的代理類就是在這時候動態生成了,我們調用該代理對象的函數就會調用到中間類的invoke函數,而invoke函數實現調用委托類的對應函數;

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
loader是類加載器;
interfaces是委托類的接口,生成代理需要實現這個接口;

實際上Java的動態代理就是兩層的靜態代理:開發者提供一個委托類A,程序動態生成了一個代理類B,開發者還需要提供一個實現了InvocationHandler的接口C,用類C來連接委托類A和委托類B,類C是代理類B的委托類,是類A的代理類;用戶直接調用代理類B,B將調用轉發給委托類C,C再將調用轉發給委托類A;

參考:
《Java編程思想》第四版
公共技術點之 Java 動態代理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM