zoukankan      html  css  js  c++  java
  • Java反射机制记录

    Class对象获取的三种方式

    Java反射操作都需要首先获取Class对象。获取Class对象的方式有三种:

    1. 公有属性class
    2. 方法getClass()
    3. Class.forName()

    示例:

    public class ReflectClassDemo {
        /** log4j */
        private static final Logger LOGGER = Logger.getLogger(ReflectClassDemo.class);
        /**
        * <p>获取Class对象的三种方式</p>
        * @author*/
        public static void main(String[] args) throws ClassNotFoundException {
            LOGGER.info("获取Class对象方式01:类的public属性class");
            Class clazz1 = User.class;
            LOGGER.info(clazz1);
    
            System.out.println();
            LOGGER.info("获取Class对象方式02:类的public方法getClass()");
            User user = new User();
            Class clazz2 = user.getClass();
            LOGGER.info(clazz2);
    
            System.out.println();
            LOGGER.info("获取Class对象方法03:Class.forName(需要抛出异常)");
            Class clazz3 = Class.forName("pers.hanchao.reflect.common.User");
            LOGGER.info(clazz3);
        }
    }

    运行结果:

    2018-02-24 13:59:06 INFO  ReflectClassDemo:18 - 获取Class对象方式01:类的public属性class
    2018-02-24 13:59:06 INFO  ReflectClassDemo:20 - class pers.hanchao.reflect.common.User
    
    2018-02-24 13:59:06 INFO  ReflectClassDemo:23 - 获取Class对象方式02:类的public方法getClass()
    2018-02-24 13:59:06 INFO  ReflectClassDemo:26 - class pers.hanchao.reflect.common.User
    
    2018-02-24 13:59:06 INFO  ReflectClassDemo:29 - 获取Class对象方法03:Class.forName(需要抛出异常)
    2018-02-24 13:59:06 INFO  ReflectClassDemo:31 - class pers.hanchao.reflect.common.User

    总结:

    1. 通过公有属性class获取Class对象:通过类获取,无需创建类对象。
    2. 通过方法getClass()获取Class对象:需要类的对象。常用于不知道类名但是能获取对象的情况下。
    3. 通过方法Class.forName()获取Class对象:需要类的全名,需抛出异常。常用于加载配置。

    通过反射实例化对象的两种方式

    除了通过new实例化对象,我们还可以通过反射实例化对象对象,有两种方式:

    1. Class.newInstance()
    2. Constructor.newInstance()

    示例:

    public class CreateObjectDemo {
        private final static Logger LOGGER = Logger.getLogger(CreateObjectDemo.class);
    
        /**
         * <p>Title: 通过反射创建对象的两种方式</p>
         * @author*/
        public static void main(String[] args) throws Exception {
            //通过new实例化对象
            User user = new User();
            LOGGER.info("通过new实例化对象:" + user.toString());
    
            //通过反射实例化对象
            Class userClass = User.class;
            //通过反射实例化对象01-Class.newInstance()(需要强制类型转换[无参构造])
            User user1 = (User) userClass.newInstance();
            LOGGER.info("通过反射实例化对象01-Class.newInstance()(需要强制类型转换[无参构造]):" + user1.toString());
    //通过反射实例化对象02-Constructor.newInstance()(需要强制类型转换[可带参数]) Constructor constructor = userClass.getDeclaredConstructor(); User user2 = (User) constructor.newInstance(); LOGGER.info("通过反射实例化对象02-Constructor.newInstance()(需要强制类型转换[无参构造]):" + user2.toString());
    Constructor constructor1
    = userClass.getDeclaredConstructor(String.class,String.class); User user3 = (User) constructor1.newInstance("李四","000000"); LOGGER.info("通过反射实例化对象02-Constructor.newInstance()(需要强制类型转换[有参构造]):" + user3.toString()); } }

    补充:通过构造函数去创建,调用Constructor对象的newInstance()方法创建对象。

    Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
    Chinese chinese=(Chinese) c1.getConstructor().newInstance();
    chinese.say();

    运行结果:

    2018-02-24 14:23:29 INFO  CreateObjectDemo:22 - 通过new实例化对象:User{username='张三', password='123456'}
    2018-02-24 14:23:29 INFO  CreateObjectDemo:27 - 通过反射实例化对象01-Class.newInstance()(需要强制类型转换[无参构造]):User{username='张三', password='123456'}
    2018-02-24 14:23:29 INFO  CreateObjectDemo:31 - 通过反射实例化对象02-Constructor.newInstance()(需要强制类型转换[无参构造]):User{username='张三', password='123456'}
    2018-02-24 14:23:29 INFO  CreateObjectDemo:34 - 通过反射实例化对象02-Constructor.newInstance()(需要强制类型转换[有参构造]):User{username='李四', password='000000'}

    总结:

    1. 通过Class.newInstance()进行对象实例化:实际调用的是无参数的构造函数进行实例化。
    2. 通过Constructor.newInstance()进行对象实例化:可以选择调用哪个构造函数进行实例化。

     

    获取某个类的所有构造方法

    public class ReflectTest1 {
        public static void main(String[] args) {
            Date date = new Date();
            Class cc = date.getClass();
            String className = cc.getName();
            System.out.println(className);
            Constructor[] declaredConstructors = cc.getDeclaredConstructors();
            for (Constructor constructor : declaredConstructors) {
                int modifiers = constructor.getModifiers();
                System.out.print(Modifier.toString(modifiers) + " ");
                System.out.print(constructor.getName() + "(");
                Class[] paramTypes = constructor.getParameterTypes();
                for (Class paramType : paramTypes) {
                    System.out.print(paramType.getName() + " ");
                }
                System.out.println(")");
            }
        }
    }

    输出结果:

    java.util.Date
    public java.util.Date(java.lang.String )
    public java.util.Date(int int int int int int )
    public java.util.Date(int int int int int )
    public java.util.Date()
    public java.util.Date(long )
    public java.util.Date(int int int )

    获取某个类的所有属性信息

    public class ReflectTest2 {
        public static void main(String[] args) {
            Date date = new Date();
            Class cc = date.getClass();
            String className = cc.getName();
            System.out.println(className);
            Field[] fields = cc.getDeclaredFields();
            for (Field field : fields) {
                String modifiers = Modifier.toString(field.getModifiers());
                Class type = field.getType();
                String name = field.getName();
                System.out.println(modifiers + " " + type.getName() + " " + name);
            }
        }
    }

    输出结果:

    java.util.Date
    private static final sun.util.calendar.BaseCalendar gcal
    private static sun.util.calendar.BaseCalendar jcal
    private transient long fastTime
    private transient sun.util.calendar.BaseCalendar$Date cdate
    private static int defaultCenturyStart
    private static final long serialVersionUID
    private static final [Ljava.lang.String; wtb
    private static final [I ttb

    补充:

    1、获取所有非private类型的字段,包括父类的
         Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
         Object object=    c1.getConstructor().newInstance();
         Field [] fields=  c1.getFields();//或者所有的非private类型的字段,包括父类的
         for(int i=0;i<fields.length;i++)
         {
             System.out.println(fields[i].getName());
         }
         
    2、获取当前类所有字段,包括私有的
         Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
         Object object=    c1.getConstructor().newInstance();
         Field [] fields=  c1.getDeclaredFields();//获取当前类中所有的字段
         for(int i=0;i<fields.length;i++)
         {
             System.out.println(fields[i].getName());
         }
         
    3、获取父类的所有字段,包括私有的
    
            Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
            Class c2=    c1.getSuperclass();
            //通过c2去获取父类中的私有字段
    4、获取指定的字段
         Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
         Object object=    c1.getConstructor().newInstance();
         Field field=  c1.getDeclaredField("Age");
    
    5、使用
         Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
         Object object1=    c1.getConstructor().newInstance();
         Field field=  c1.getDeclaredField("Age");
         field.setAccessible(true);//如果字段是私有的,需要先这是允许访问
         //取值
         Object  object2=field.get(object1);
         System.out.println(object2);
         //赋值
         field.set(object1, 21);
         //取值
         Object  object3=field.get(object1);
         System.out.println(object3);

    获取某个类的所有方法信息

    public class ReflectTest3 {
        public static void main(String[] args) {
            Date date = new Date();
            Class cc = date.getClass();
            Method[] methods = cc.getDeclaredMethods();
            for (Method method : methods) {
                String modifiers = Modifier.toString(method.getModifiers());
                Class returnType = method.getReturnType();
                String name = method.getName();
                Class[] parameterTypes = method.getParameterTypes();
                Class[] exceptions = method.getExceptionTypes();
                System.out.println(modifiers + " " + returnType + " " + name
                        + "(" + Arrays.asList(parameterTypes) + ")throws" + Arrays.asList(exceptions));
            }
        }
    }

    输出结果:

    public boolean after([class java.util.Date])throws[]
    public boolean before([class java.util.Date])throws[]
    public boolean equals([class java.lang.Object])throws[]
    public class java.lang.String toString([])throws[]
    public int hashCode([])throws[]
    public class java.lang.Object clone([])throws[]
    public volatile int compareTo([class java.lang.Object])throws[]
    public int compareTo([class java.util.Date])throws[]
    ······

    补充:获取方法并执行

    1、获取所有的非private方法
            Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
            Object chinese= c1.getConstructor().newInstance();
            Method[] methods1= c1.getMethods();//获取所有的非private方法,并且父类的方法也会获取
            for(int i=0;i<methods1.length;i++)
            {
                Class[] parameters= methods1[i].getParameterTypes();
                if(parameters.length<=0)
                {
                     System.out.println(methods1[i].getName()+"()");
                }
                else
                {
                    String [] typeName=new String[parameters.length];
                    for(int j=0;j<parameters.length;j++)
                    {
                        
                        typeName[j]=parameters[j].getSimpleName();
                    }
                    System.out.println(methods1[i].getName()+"("+String.join(",",typeName)+")");
                }
    
            }
    
    2、获取所有的当前类定义的所有方法,包括私有方法
            Method[] methods1= c1.getDeclaredMethods();//获取当前类定义的所有,包括私有方法
    3、获取指定方法名的方法
            Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
            Object chinese= c1.getConstructor().newInstance();
            Method setNumber=    c1.getDeclaredMethod("setNumber", Integer.class);//如果方法没有参数就可以不用写,另外需要注意参数类型和定义方法的参数类型保持一致
    
    4、获取父类的私有方法
            Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
            Class c2=    c1.getSuperclass();
            //通过c2去获取父类中的私有方法
    
    5、执行方法
            Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
            Object chinese= c1.getConstructor().newInstance();
            Method setNumber=    c1.getDeclaredMethod("setNumber", Integer.class);//如果方法没有参数就可以不用写,另外需要注意参数类型和定义方法的参数类型保持一致
            setNumber.invoke(chinese, 1);    //第一个参数是实例对象,后面的参数是调用方法所需的参数

    动态代理

    代理是基本的设计模式之一。
    下面是一个用来展示代理结构的简单示例:

    interface Interface {
      void doSomething();
      void somethingElse(String arg);
    }
    
    class RealObject implements Interface {
      public void doSomething() { System.out.println("doSomething"); }
      public void somethingElse(String arg) {
        System.out.println("somethingElse " + arg);
      }
    }    
    
    class SimpleProxy implements Interface {
      private Interface proxied;
      public SimpleProxy(Interface proxied) {
        this.proxied = proxied;
      }
      public void doSomething() {
        System.out.println("SimpleProxy doSomething");
        proxied.doSomething();
      }
      public void somethingElse(String arg) {
        System.out.println("SimpleProxy somethingElse " + arg);
        proxied.somethingElse(arg);
      }
    }    
    
    class SimpleProxyDemo {
      public static void consumer(Interface iface) {
        iface.doSomething();
        iface.somethingElse("bonobo");
      }
      public static void main(String[] args) {
        consumer(new RealObject());
        consumer(new SimpleProxy(new RealObject()));
      }
    }

    输出结果:

    doSomething
    somethingElse bonobo
    SimpleProxy doSomething
    doSomething
    SimpleProxy somethingElse bonobo
    somethingElse bonobo

    Java的动态代理比代理的思想更向前迈进了一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理所做的所有调用都会被重定向到单一的调用处理器上。

    import java.lang.reflect.*;
    
    class DynamicProxyHandler implements InvocationHandler {
      private Object proxied;
      public DynamicProxyHandler(Object proxied) {
        this.proxied = proxied;
      }
      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(proxied, args);
      }
    }    
    
    class SimpleDynamicProxy {
      public static void consumer(Interface iface) {
        iface.doSomething();
        iface.somethingElse("bonobo");
      }
      public static void main(String[] args) {
        RealObject real = new RealObject();
        consumer(real);
        // Insert a proxy and call again:
        Interface proxy = (Interface)Proxy.newProxyInstance(
          Interface.class.getClassLoader(),
          new Class[]{ Interface.class },
          new DynamicProxyHandler(real));
        consumer(proxy);
      }
    }

    输出结果:

    doSomething
    somethingElse bonobo
    **** proxy: class $Proxy0, method: public abstract void Interface.doSomething(), args: null
    doSomething
    **** proxy: class $Proxy0, method: public abstract void Interface.somethingElse(java.lang.String), args: [Ljava.lang.Object;@53bd815b
      bonobo
    somethingElse bonobo

    通过调用静态方法Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器。
    动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造器传递给一个“实际”对象的引用,从而使得调用处理器在执行其中任务时,可以将请求转发。

    空对象

    当你使用内置的null表示缺少对象时,在每次使用引用时都必须测试其是否为null,这显得枯燥,而且势必产生相当乏味的代码。问题在于null除了在你试图用它执行任何操作来产生NullPointerException之外,它自己没有其他任何行为。有时引入空对象的思想将会很有用,它可以接受传递给它的所代表的对象的消息,但是将返回表示为实际上并不存在任何“真实”对象的值。通过这种方式,你可以假设所有的对象都是有效的,而不必浪费编程精力去检查null
    推荐阅读:java设计模式之空对象模式

  • 相关阅读:
    《软件开发这点事儿》作者在MSDN上与您讨论软件开发
    JavaScript的对象观
    Windows操作系统发展简史
    UCenter Home 1.5的基本配置与技巧
    设计模式模版方法(TemplateMethod)
    设计模式访问者模式(Visitor)
    设计模式状态模式(State)
    Ext终于开始收费了
    设计模式观察者模式(Observer)
    设计模式备忘录模式(Memento)
  • 原文地址:https://www.cnblogs.com/xiejn/p/14206109.html
Copyright © 2011-2022 走看看