多态经过分离作什么和怎么作,从另外一个角度将接口与实现分离开来;经过多态来消除类型之间的耦合关系,在Java中,多态也叫动态绑定,后期绑定或运行时绑定,那么什么是方法绑定?java
将一个方法与调用同一个方法的主体关联起来被称为绑定;若在程序执行前进行绑定(由编译器和链接程序实现),叫作前期绑定;还有一种叫后期绑定,就是在运行时根据对象的类型进行绑定,也叫动态绑定或运行时绑定,也就是说,编译器不知道对象的类型,可是方法调用机制能找到正确的方法体;在Java中除了static
方法和final
方法以外,全部的其余方法都是后期绑定;编程
所以,Java中全部的方法都是经过动态绑定来实现多态的,但若是直接访问某个域,则这个访问就会在编译其进行解析;通常咱们都经过将子类向上转型为父类来实现多态,父类能够是抽象类,只要子类实现到父类的全部抽象方法,就能够将子类转型为抽象的父类;Java里的抽象类自己是不能被实例化,但能够将子类的引用向上转型为抽象的父类。
如:ide
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反射提供的功能包括:this
咱们想获得一个类的全部信息,第一步就是要获得类的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编程思想》第四版)code
下面简要介绍利用反射实现的动态代理;对象
步骤:接口
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 动态代理