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设计模式之空对象模式

  • 相关阅读:
    49. 字母异位词分组
    73. 矩阵置零
    Razor语法问题(foreach里面嵌套if)
    多线程问题
    Get json formatted string from web by sending HttpWebRequest and then deserialize it to get needed data
    How to execute tons of tasks parallelly with TPL method?
    How to sort the dictionary by the value field
    How to customize the console applicaton
    What is the difference for delete/truncate/drop
    How to call C/C++ sytle function from C# solution?
  • 原文地址:https://www.cnblogs.com/xiejn/p/14206109.html
Copyright © 2011-2022 走看看