Java reflection mechanism record

Three methods of obtaining Class objects

Java reflection operations need to get the Class object first. There are three ways to obtain Class objects:

  1. Public attribute class
  2. Method getClass()
  3. Class.forName()

Example:

public class ReflectClassDemo {
    /** log4j */
    private static final Logger LOGGER = Logger.getLogger(ReflectClassDemo.class);
    /**
    * <p>Three ways to get Class objects</p>
    * @author*/
    public static void main(String[] args) throws ClassNotFoundException {
        LOGGER.info("obtain Class Object mode 01: Class public attribute class");
        Class clazz1 = User.class;
        LOGGER.info(clazz1);

        System.out.println();
        LOGGER.info("obtain Class Object mode 02: Class public method getClass()");
        User user = new User();
        Class clazz2 = user.getClass();
        LOGGER.info(clazz2);

        System.out.println();
        LOGGER.info("obtain Class Object method 03: Class.forName((exception needs to be thrown)");
        Class clazz3 = Class.forName("pers.hanchao.reflect.common.User");
        LOGGER.info(clazz3);
    }
}

Operation results:

2018-02-24 13:59:06 INFO  ReflectClassDemo:18 - obtain Class Object mode 01: Class public attribute 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 - obtain Class Object mode 02: Class public method 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 - obtain Class Object method 03: Class.forName((exception needs to be thrown)
2018-02-24 13:59:06 INFO  ReflectClassDemo:31 - class pers.hanchao.reflect.common.User

Summary:

  1. Get class object through public attribute class: get class object without creating class object.
  2. Get the Class object through the method getClass(): the object that needs the Class. It is often used when the Class name is unknown but the object can be obtained.
  3. Get the Class object through the method Class.forName(): you need the full name of the Class and throw an exception. Commonly used to load configurations.

There are two ways to instantiate objects through reflection

In addition to instantiating objects through new, we can also instantiate objects through reflection in two ways:

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

Example:

public class CreateObjectDemo {
    private final static Logger LOGGER = Logger.getLogger(CreateObjectDemo.class);

    /**
     * <p>Title: There are two ways to create objects through reflection</p>
     * @author*/
    public static void main(String[] args) throws Exception {
        //Instantiate objects through new
        User user = new User();
        LOGGER.info("adopt new Instantiate object:" + user.toString());

        //Instantiate objects by reflection
        Class userClass = User.class;
        //Instantiate object 01-Class.newInstance() through reflection (need to cast [parameterless construction])
        User user1 = (User) userClass.newInstance();
        LOGGER.info("Instancing objects by reflection 01-Class.newInstance()(Cast required[Nonparametric structure]): " + user1.toString());
        //Instantiate the object through reflection (02-Constructor.newInstance() (requires forced type conversion [can take parameters])
        Constructor constructor = userClass.getDeclaredConstructor();
        User user2 = (User) constructor.newInstance();
        LOGGER.info("Instancing objects by reflection 02-Constructor.newInstance()(Cast required[Nonparametric structure]): " + user2.toString());
        Constructor constructor1 = userClass.getDeclaredConstructor(String.class,String.class);
        User user3 = (User) constructor1.newInstance("Li Si","000000");
        LOGGER.info("Instancing objects by reflection 02-Constructor.newInstance()(Cast required[Parametric structure]): " + user3.toString());
    }
}

Supplement: create the object through the Constructor and call the newInstance() method of the Constructor object to create the object.

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

Operation results:

2018-02-24 14:23:29 INFO  CreateObjectDemo:22 - adopt new Instantiate object: User{username='Zhang San', password='123456'}
2018-02-24 14:23:29 INFO  CreateObjectDemo:27 - Instancing objects by reflection 01-Class.newInstance()(Cast required[Nonparametric structure]): User{username='Zhang San', password='123456'}
2018-02-24 14:23:29 INFO  CreateObjectDemo:31 - Instancing objects by reflection 02-Constructor.newInstance()(Cast required[Nonparametric structure]): User{username='Zhang San', password='123456'}
2018-02-24 14:23:29 INFO  CreateObjectDemo:34 - Instancing objects by reflection 02-Constructor.newInstance()(Cast required[Parametric structure]): 

Summary:

  1. Instantiate the object through Class.newInstance(): the actual call is to instantiate the parameterless constructor.
  2. Object instantiation through Constructor.newInstance(): you can choose which constructor to call for instantiation.

Gets all constructors of a class

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(")");
        }
    }
}

Output results:

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 )

Get all attribute information of a class

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);
        }
    }
}

Output results:

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

Supplement:

1,Get all non private Fields of type, including those of the parent class
     Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
     Object object=    c1.getConstructor().newInstance();
     Field [] fields=  c1.getFields();//Or all non private fields, including those of the parent class
     for(int i=0;i<fields.length;i++)
     {
         System.out.println(fields[i].getName());
     }
     
2,Gets all fields of the current class, including private fields
     Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
     Object object=    c1.getConstructor().newInstance();
     Field [] fields=  c1.getDeclaredFields();//Gets all fields in the current class
     for(int i=0;i<fields.length;i++)
     {
         System.out.println(fields[i].getName());
     }
     
3,Gets all fields of the parent class, including private fields

        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Class c2=    c1.getSuperclass();
        //Get the private fields in the parent class through c2
4,Gets the specified field
     Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
     Object object=    c1.getConstructor().newInstance();
     Field field=  c1.getDeclaredField("Age");

5,use
     Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
     Object object1=    c1.getConstructor().newInstance();
     Field field=  c1.getDeclaredField("Age");
     field.setAccessible(true);//If the field is private, you need to allow access first
     //Value
     Object  object2=field.get(object1);
     System.out.println(object2);
     //assignment
     field.set(object1, 21);
     //Value
     Object  object3=field.get(object1);
     System.out.println(object3);

Get all method information of a class

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));
        }
    }
}

Output results:

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[]
······

Supplement: obtain method and execute

1,Get all non private method
        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Object chinese= c1.getConstructor().newInstance();
        Method[] methods1= c1.getMethods();//Get all non private methods, and the methods of the parent class will also get
        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,Gets all methods defined by the current class, including private methods
        Method[] methods1= c1.getDeclaredMethods();//Gets all of the current class definition, including private methods
3,Gets the method of the specified method name
        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Object chinese= c1.getConstructor().newInstance();
        Method setNumber=    c1.getDeclaredMethod("setNumber", Integer.class);//If the method does not have parameters, you can not write them. In addition, you need to pay attention to the consistency between the parameter type and the parameter type defining the method

4,Gets the private method of the parent class
        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Class c2=    c1.getSuperclass();
        //Get the private method in the parent class through c2

5,Execution method
        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Object chinese= c1.getConstructor().newInstance();
        Method setNumber=    c1.getDeclaredMethod("setNumber", Integer.class);//If the method does not have parameters, you can not write them. In addition, you need to pay attention to the consistency between the parameter type and the parameter type defining the method
        setNumber.invoke(chinese, 1);    //The first parameter is the instance object, and the following parameters are the parameters required to call the method

Tulai

Dynamic agent

Agent is one of the basic design patterns.
The following is a simple example to show the agent structure:

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()));
  }
}

Output results:

doSomething
somethingElse bonobo
SimpleProxy doSomething
doSomething
SimpleProxy somethingElse bonobo
somethingElse bonobo

Java's dynamic proxy is a step forward from the idea of proxy, because it can dynamically create a proxy and dynamically handle the calls to the proxy methods. All calls made in the dynamic agent are redirected to a single call processor.

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);
  }
}

Output results:

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

You can create a dynamic proxy by calling the static method * * Proxy.newProxyInstance() * * which requires a class loader.
The dynamic proxy can redirect all calls to the calling processor, so it usually passes a reference to an "actual" object to the constructor of the calling processor, so that the calling processor can forward the request when performing its tasks.

Empty object

When you use the built-in null to represent the missing object, you must test whether it is null every time you use the reference, which is boring and is bound to produce quite boring code. The problem is that null has no behavior of its own except when you try to do anything with it to generate a NullPointerException. Sometimes it is useful to introduce the idea of an empty object, which can accept the message passed to the object it represents, but will return a value that represents that there is actually no "real" object. In this way, you can assume that all objects are valid without wasting programming energy checking for nulls.

Tags: Java

Posted on Thu, 23 Sep 2021 19:36:40 -0400 by stewartship