zoukankan      html  css  js  c++  java
  • Java反射与动态代理

    1.Java反射

    当通过反射与一个未知类型的对象打交道时,JVM只简单地检查这个对象,看它属于哪个特定的类。在用它做其他事情之前必须先加载那个类的Class对象。

    当使用反射时,就可以在运行时获取类信息,对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。

    下面就是一个反射的例子,通过反射输出了该类的所有方法和构造器,然后通过反射调用了该类的方法。从输出结果可以看出,通过反射获取到了运行类的所有方法信息和构造函数信息,还通过反射机制调用了该类的方法,进行了输出。

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.regex.Pattern;
    
    public class ShowMethods {
        private static String usage = "usage";
        private static Pattern p = Pattern.compile("\w+\.");
    
        public void method1() {
            System.out.println("我被调用啦");
        }
    
        public void method2(int num) {
            System.out.println(num);
        }
    
        public static void main(String[] args) {
            try {
                ShowMethods showMethods = new ShowMethods();
                System.out.println(showMethods.getClass().getName());
    			// 加载该类
                Class<?> c = Class.forName("reflect.ShowMethods");
    			// 获取该类所有的方法
                Method[] methods = c.getMethods();
    			// 获取该类所有的构造函数
                Constructor[] constructors = c.getConstructors();
                for (Method method : methods) {
                    System.out.println(p.matcher(method.toString()).replaceAll(" "));
                }
                for (Constructor constructor : constructors) {
                    System.out.println(p.matcher(constructor.toString()).replaceAll(" "));
                }
    			// 获取该类的method1方法
                Method method1 = c.getMethod("method1");
    			// 调用无参方法
                method1.invoke(c.newInstance());
    			// 获取该类的method2方法
                Method method2 = c.getMethod("method2", int.class);
    			// 调用有参方法,传入参数20
                method2.invoke(c.newInstance(), 20);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    

    输出结果如下:

    reflect.ShowMethods
    public static void   main(  String[])
    public void   method1()
    public void   method2(int)
    public final void    wait() throws   InterruptedException
    public final void    wait(long,int) throws   InterruptedException
    public final native void    wait(long) throws   InterruptedException
    public boolean    equals(  Object)
    public   String    toString()
    public native int    hashCode()
    public final native   Class    getClass()
    public final native void    notify()
    public final native void    notifyAll()
    public  ShowMethods()
    我被调用啦
    20
    

    2.代理模式

    静态代理

    由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

    Subject接口

    public interface Subject {
        void request();
    }
    

    RealSubject类

    public class RealSubject implements Subject {
        @Override
        public void request() {
            System.out.println("RealSubject");
        }
    }
    

    代理类

    public class Proxy implements Subject {
        private Subject subject;
    
        public Proxy(Subject subject) {
            this.subject = subject;
        }
    
        @Override
        public void request() {
            System.out.println("begin");
            subject.request();
            System.out.println("end");
        }
    }
    

    测试类

    public class ProxyTest {
        public static void main(String[] args) {
            RealSubject realSubject = new RealSubject();
            Proxy proxy = new Proxy(realSubject);
            proxy.request();
        }
    }
    

    动态代理

    动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。

    同样实现上面的结构。

    public interface Subject {
        void doSomething();
    }
    
    public class RealSubject implements Subject {
        public void doSomething() {
            System.out.println("我正在做某事");
        }
    }
    

    代理类

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class SubjectProxy implements InvocationHandler {
        private Object target;
    
        public SubjectProxy(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("begin");
            Object result = method.invoke(target, args);
            System.out.println("end");
            return result;
        }
    
        public Object getProxy() {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Class<?>[] interfaces = target.getClass().getInterfaces();
            return Proxy.newProxyInstance(classLoader, interfaces, this);
        }
    }
    
    public class SubjectTest {
        public static void main(String[] args) {
            RealSubject realSubject = new RealSubject();
            SubjectProxy subjectProxy = new SubjectProxy(realSubject);
            Subject subject = (Subject)subjectProxy.getProxy();
            subject.doSomething();
        }
    }
    

    优点:动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理。

    不足:始终无法摆脱仅支持 interface 代理的桎梏。

  • 相关阅读:
    SQL Server 2008 允许远程链接 解决方法
    对上传图片进行剪切的jquery插件
    解决在IE6 下,css中的position:fixed 不起作用的办法
    对网站搞评比投票活动的总结
    关于设置sql server 2008服务器属性时出现的无法加载xplog70.dll文件的问题
    Android LayoutInflater的使用
    在Android中查看和管理sqlite数据库
    android开发的WARNING: Could not initialize OpenglES emulation, using software renderer问题的解决
    Android 常用错误及解决方法
    解决MyEclipse启动速度慢,提高MyEclipse启动速度
  • 原文地址:https://www.cnblogs.com/liuyang0/p/6606241.html
Copyright © 2011-2022 走看看