zoukankan      html  css  js  c++  java
  • Java编程思想——第14章 类型信息(二)反射

    六、反射:运行时的类信息

      我们已经知道了,在编译时,编译器必须知道所有要通过RTTI来处理的类。而反射提供了一种机制——用来检查可用的方法,并返回方法名。区别就在于RTTI是处理已知类的,而反射用于处理未知类。Class类与java.lang.reflect类库一起对反射概念进行支持,该类库包含Field、Method以及Constructor(每个类都实现了Member接口)。这些类型是由JVM运行时创建的,用来表示未知类种对应的成员。使用Constructor(构造函数)创建新的对象,用get(),set()方法读取和修改与Field对象(字段)关联的字段,用invoke()方法调用与Method对象(方法)关联的方法。这样,匿名对象的类信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

      其实,当反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,在做其他事情之前必须先加载这个类的Class对象。因此,那个类的.class文件对于JVM来说必须时可获取的(在本地或网络上)所以反射与RTTI的区别只在于:对于RTTI来说,编译器在编译时打开和检查.class文件,而对于反射来说,.class文件在编译时是不可获得的,所以是运行时打开和检查.class文件。反射在需要创建更动态的代码时很有用。

    七、动态代理

      代理是基本的设计模式:为其他对象提供一种代理,以便控制对象,而在对象前或后加上自己想加的东西。

    interface Interface {
        void doSomething();
    
        void doSomeOtherThing(String args);
    }
    
    class RealObject implements Interface {
    
        @Override
        public void doSomething() {
            System.out.println("doSomething");
        }
    
        @Override
        public void doSomeOtherThing(String args) {
            System.out.println("doSomeOtherThing" + args);
        }
    }
    
    class SimpleProxy implements Interface {
    
        private Interface proxyId;
    
        public SimpleProxy(Interface proxyId) {
            this.proxyId = proxyId;
        }
    
        @Override
        public void doSomething() {
            //将原有的doSomething 方法添加上了一个输出 这就是代理之后新增的东西
            //就好比某公司代理游戏后加的内购
            System.out.println("SimpleProxy doSomething");
            proxyId.doSomething();
        }
    
        @Override
        public void doSomeOtherThing(String args) {
            proxyId.doSomeOtherThing(args);
            //新增的东西可以在原有之前或之后都行
            System.out.println("SimpleProxy doSomeOtherThing" + args);
        }
    }
    
    public class SimpleProxyDemo {
        static void consumer(Interface i) {
            i.doSomething();
            i.doSomeOtherThing(" yi gi woli giao");
        }
    
        public static void main(String[] args) {
            consumer(new RealObject());
            System.out.println("-----  -----  -----");
            consumer(new SimpleProxy(new RealObject()));
        }
    }

    结果:

    doSomething
    doSomeOtherThing yi gi woli giao
    -----  -----  -----
    SimpleProxy doSomething
    doSomething
    doSomeOtherThing yi gi woli giao
    SimpleProxy doSomeOtherThing yi gi woli giao

      因为consumer()接受的Interface,所以无论是RealObject还是SimpleProxy,都可以作为参数,而SimpleProxy插了一脚 代理了RealObject加了不少自己的东西。

      java的动态代理更前进一步,因为它可以动态创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    interface Interface {
        void doSomething();
    
        void doSomeOtherThing(String args);
    }
    
    class RealObject implements Interface {
    
        @Override
        public void doSomething() {
            System.out.println("doSomething");
        }
    
        @Override
        public void doSomeOtherThing(String args) {
            System.out.println("doSomeOtherThing" + args);
        }
    }
    
    class DynamicProxyHandler implements InvocationHandler {
        private Object proxyId;
    
        public DynamicProxyHandler(Object proxyId) {
            this.proxyId = proxyId;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("**** proxy:" + proxy.getClass() + ", method" + method + ", args:" + args);
            if (args != null) {
                for (Object arg : args) {
                    System.out.println(" " + arg);
                }
            }
            return method.invoke(proxyId, args);
        }
    }
    
    public class SimpleProxyDemo {
        static void consumer(Interface i) {
            i.doSomething();
            i.doSomeOtherThing(" yi gi woli giao");
        }
    
        public static void main(String[] args) {
            RealObject realObject = new RealObject();
            consumer(realObject);
            System.out.println("-----  -----  -----");
         //动态代理 可以代理任何东西 Interface proxy
    = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandler(realObject)); consumer(proxy); } }

    结果:

    doSomething
    doSomeOtherThing yi gi woli giao
    -----  -----  -----
    **** proxy:class $Proxy0, methodpublic abstract void Interface.doSomething(), args:null
    doSomething
    **** proxy:class $Proxy0, methodpublic abstract void Interface.doSomeOtherThing(java.lang.String), 
    args:[Ljava.lang.Object;@7ea987ac  yi gi woli giao
    doSomeOtherThing yi gi woli giao

    通过Proxy.newProxyInstance()可以创建动态代理,这个方法需要三个参数:

    1. 类加载器:可以从已经被加载的对象中获取其类加载器;

    2. 你希望该代理实现的接口列表(不可以是类或抽象类,只能是接口);

    3. InvocationHandler接口的一个实现;

    在 invoke 实现中还可以根据方法名处对不同的方法进行处理,比如:

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("**** proxy:" + proxy.getClass() + ", method" + method + ", args:" + args);
            if (args != null) {
                for (Object arg : args) {
                    System.out.println(" " + arg);
                }
            }
            if (method.getName().equals("doSomething")) {
                System.out.println("this is the proxy for doSomething");
            }
            return method.invoke(proxyId, args);
        }

    还可以对参数或方法进行更多的操作因为 你已经得到了他们 尽情的使用你的代理权吧 ~~ 先加它十个内购。

    九、接口与类型信息

      interface关键字的一种重要目标就是允许程序员隔离构件,进而降低耦合。反射,可以调用所有方法,甚至是private。唯独final是无法被修改的,运行时系统会在不抛任何异常的情况接受任何修改尝试,但是实际上不会发生任何修改。

        void callMethod(Object a, String methodName) throws Exception {
            Method method = a.getClass().getDeclaredMethod(methodName);
            method.setAccessible(true);
            method.invoke(a);
        }

      

  • 相关阅读:
    SpringCloud组件---Ribbon
    SpringCloud组件---Eureka
    tomcat及Jetty远程调试debug
    mysql 删除重复数据
    mysql执行SQL语句时报错:[Err] 3
    线程池原理剖析
    上限下限
    线程池Executors、Callable与Future的应用
    spring获取bean(自定义工具类)
    java.util.concurrent.Exchanger应用范例
  • 原文地址:https://www.cnblogs.com/xcgShare/p/11837319.html
Copyright © 2011-2022 走看看