zoukankan      html  css  js  c++  java
  • 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 动态代理

  • 相关阅读:
    suse linux编译安装GCC报错
    suse linux 编译安装Apache时报“APR NOT FOUND”的解决方法
    LoadRunner监控Windows和Linux常见问题
    LR报-27727错误解决办法
    主机在virtualbox在NAT方式SSH访问
    清除hao123浏览器劫持小尾巴病毒
    在CentOS上,Servlet出现java.lang.NoClassDefFoundError
    构建第一个SSH的maven项目
    关于Oracle数据库sys用户登入的解惑
    ip route-static 命令的参数
  • 原文地址:https://www.cnblogs.com/WoodJim/p/4722107.html
Copyright © 2011-2022 走看看