Java reflection -- Reflection and class operation

Keywords: Java JDK jvm Oracle

Content learned in: edu.aliyun.com


1. Reflection acquisition class structure

                             .

   if you suddenly find that you need to do a deeper analysis of binary files in future development, then you have two options:

  • Option 1: read and analyze binary byte stream data through Oracle's official standard:
  • Option 2: use some third-party toolkits (Java dependency), which can implement the analysis of "*. class" files.

                            

  • Get the package name of the program: public String getPackageName()
  • Get inherited parent class: public class <? Super T > getsuperclass()
  • Get all parent interfaces: public class <? > [] getinterfaces()

The structure is as follows:

Get parent structure information:

interface IMessage {
}

interface IChannel {
}

abstract class AbstaractChannelMessage implements IMessage, IChannel {
}

class CloudMessage extends AbstaractChannelMessage implements IMessage, IChannel {
}


public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = CloudMessage.class;
        System.out.println("[Get package name]:" + clazz.getPackage().getName());
        System.out.println("[Get inherited parent]:" + clazz.getSuperclass().getName());
        System.out.println("[Get implementation interface]:" + Arrays.toString(clazz.getInterfaces()));
    }
}

Result:

[get package name]: com.xzzz.demo
[get inherited parent class]: com.xzzz.demo.AbstaractChannelMessage
[get implementation interface]: [interface com.xzzz.demo.IMessage, interface com.xzzz.demo.IChannel]

                         .

2. Reflection call construction method

                         

No. Method name type describe
01 public Constructor getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException Method Gets the specified construction method (public) according to the specified parameter type
02 public Constructor<?>[] getConstructors() throws SecurityException Method Get all construction methods of the class (public)
03 public Constructor getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException Method Gets the specified construction method (any type) based on the specified parameter type
04 public Constructor<?>[] getDeclaredConstructors() throws SecurityException Method Get all construction methods of the class (any type)

The structural diagram is shown as follows:

Get construction information:

class CloudMessage {
    protected CloudMessage(String str){}
    private CloudMessage(){}
    CloudMessage(int a){}
    public CloudMessage(String str,int a){}
}


public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = CloudMessage.class;
        System.out.println("[Get partial construction]"+Arrays.toString(clazz.getConstructors()));
        System.out.println("[Get all constructs]"+Arrays.toString(clazz.getDeclaredConstructors()));
    }
}

Result:

[Get partial construction][public com.xzzz.demo.CloudMessage(java.lang.String,int)]
[Get all constructs][public com.xzzz.demo.CloudMessage(java.lang.String,int), com.xzzz.demo.CloudMessage(int), private com.xzzz.demo.CloudMessage(), protected com.xzzz.demo.CloudMessage(java.lang.String)]

   at this time, you can get all the construction methods of this class directly. If you want to get the parent class construction, just write the following code: clazz.getSuperclass().getConstructors()
                           .
                           

  • public T newInstance() throws InstantiationException, IllegalAccessException

                       .

Call construct:

class Ball {
    private String name;
    private double price;

    public Ball(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Ball{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}


public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Ball.class;//Get reflection object
        Constructor<?> con = clazz.getDeclaredConstructor(String.class,double.class);
        Ball ball = (Ball) con.newInstance("aaaa",1.2);
        System.out.println(ball);
    }
}

Result:

Ball{name='aaaa', price=1.2}

                     . In JDK 1.8 and earlier, there are actually two different methods for instantiation of reflection objects:

  • Class class: public T newInstance() throws InstantiationException, IllegalAccessException; the default call is parameter free construction. If there is no parameter free construction in the class, an exception will be thrown. After JDK 1.9, it will be directly modified to Constructor class call;
  • Constructor class: public t newinstance (object initargs) throws InstantiationException, llgalAccessException,
    IllegalArgumentException, InvocationTargetException;

3. Reflection calling method

In    Class, the construction method is called once when the object is instantiated, but after the object is available, the ordinary method can be called many times. Then the operation to get the method instance in the Class is also defined in the Class class.

  • Get all methods of this class: public Method[] getDeclaredMethods() throws SecurityException
  • Get a Method instance of the specified type of this class: public Method getdeclaredmethod (string name, class <? > parameterTypes) throws NoSuchMethodException, SecurityException
  • Get all public methods (including the parent class): public Method[] getMethods() throws SecurityException
  • Get a method of the specified type (including the parent class): public method getmethod (string name, class <? > parameterTypes) throws NoSuchMethodException, SecurityException

   when a Method is obtained, the Method will be described as an instance of the Method class, and the definition of this class is as follows:

  • public final class Method extends Executable

   the definition of this class is exactly the same as the previous constructor class, and the inheritance structure of this class is as follows.

Get method information:

class Ball {
}


public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Ball.class;//Get reflection object
        Method methods [] = clazz.getMethods();
        for (int i = 0;i<methods.length;i++){
            System.out.print(Modifier.toString(methods[i].getModifiers()));
            System.out.print(" "+methods[i].getReturnType().getSimpleName());
            System.out.print(" "+methods[i].getName() + " (");
            Class<?> params [] = methods[i].getParameterTypes();//Get all parameters
            for (int j = 0;j<params.length;j++){
                System.out.print(params[j].getSimpleName() + " arg-" + j);
                if (j<params.length-1){
                    System.out.print(" , ");
                }
            }
            System.out.print(")");
            Class<?> [] exps = methods[i].getExceptionTypes();//Get exception information
            if (exps.length>0){
                System.out.print(" thorws ");
            }
            for (int j = 0;j<exps.length;j++){
                System.out.print(exps[j].getSimpleName());
                if (j<params.length-1){
                    System.out.print(" , ");
                }
            }
            System.out.println();
        }
    }
}

Result:

public final native void wait (long arg-0) thorws InterruptedException
public final void wait (long arg-0 , int arg-1) thorws InterruptedException ,
public final void wait () thorws InterruptedException
public boolean equals (Object arg-0)
public String toString ()
public native int hashCode ()
public final native Class getClass ()
public final native void notify ()
public final native void notifyAll ()

                        .
   if any third-party toolkit is configured in the future, the reason why each development tool can detect the code and obtain the Method is because of the support of reflection mechanism (binary data flow parsing). But for our developers, the real meaningful code is the reflection calling Method provided in the Method class:

  • public Object invoke(Object obj, Object... args) throws llegalAccessException, IlegalArgumentException, Invocation TargetException

                     .

Call setter and getter methods with reflection:

Define a class:

package com.xzzz.vo;

public class Ball {
    private String brand;

    public String getBrand() {
        return this.brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
}

Define a tool class:

package com.xzzz.demo;

public class StringUtil {
    private StringUtil() {
    }

    public static String initcap(String str) {
        if (str == null || "".equals(str)) {
            return str;
        }
        if (str.length() == 1) {
            return str.toUpperCase();
        }
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
}

Reflection call method:

package com.xzzz.demo;

import java.lang.reflect.Method;

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        String fieldName = "brand";//Describe the properties to operate on
        String fieldValue = "I'm a brand";//Content of property
        Class<?> clazz = Class.forName("com.xzzz.vo.Ball");//Get class object
        //Whether using reflection or concrete types, there must be instanced objects
        Object obj = clazz.getDeclaredConstructor().newInstance();
        //The parameter type of the setter method cannot be obtained dynamically at this time. Fix a String.class first
        Method setMethod = clazz.getDeclaredMethod("set" + StringUtil.initcap(fieldName), String.class);
        setMethod.invoke(obj, fieldValue);//Equivalent to instanced object. Setbrand (fieldvalue)
        Method getMethod = clazz.getDeclaredMethod("get" + StringUtil.initcap(fieldName));
        Object returnObject = getMethod.invoke(obj);
        System.out.println(returnObject);
    }
}

Result:

I'm a brand

                       .

4. Reflection calling member

                            

No. Method name type describe
01 public Field[] getFields() throws SecurityException Method Get all inherited public members
02 public Field getField(String name) throws NoSuchFieldException, SecurityException Method Get a member of the specified type
03 public Field[] getDeclaredFields() throws SecurityException Method Get all the members defined by this class according to the specified parameter type
04 public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException Method Get a definition member of this class
05 public Class<?> getType() Method Get property type
06 public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException Method Get property content
07 public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException Method Set property content
08 public void setAccessible(boolean flag) Method Cancel encapsulation

The structure of   class is shown in the following figure:

Call properties in class:

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = ball.class;
        Object obj = clazz.getDeclaredConstructor().newInstance();
        Field brandField = clazz.getDeclaredField("brand");//get attribute
        brandField.setAccessible(true);//Cancel encapsulation
        System.out.println("[Member type]"+brandField.getType().getName());
        brandField.set(obj,"I'm a brand");//Equivalent to object.brand = "I am a brand"
        System.out.println(brandField.get(obj));//Equivalent to system.out.println (object. brand)
    }
}

Result:

Member type: java.lang.String
I'm a brand

5. UnSafe tools

                                   .

  • Construction method: private Unsafe() {}
  • Constant: private static final Unsafe theUnsafe = new Unsafe();

   at this time, the Unsafe class should be called through the "the Unsafe" constant object defined inside the class.

Call the method in the class:

class Singleton{
    private Singleton(){
        System.out.println("Singleton[Construction call]");
    }

    public void print(){
        System.out.println("www.mldn.cn");
    }
}
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        unsafeField.setAccessible(true);//Cancel inner encapsulation
        Unsafe unsafe =(Unsafe) unsafeField.get(null);
        Singleton instance = (Singleton) unsafe.allocateInstance(Singleton.class);
        instance.print();
    }
}

Result:

www.mldn.cn

   now we can find that using Unsafe class can break the existing model of object use in JVM, and can directly call the ordinary methods provided in class when the object is not instantiated, but such operation means that all processing is completed by the program itself, and all code is not controlled by the JVM, which means that all garbage collection mechanisms will be lost effect
Explanation significance: Unsafe only provides a kind of support for direct object operation at the bottom, which is not significant for actual development. If you are required to write a singleton design pattern in the future during the written test, please pay attention to the following points: to use lazy singleton design, to process the data synchronization, and to supplement the use of Unsafe to bypass the object instantiation mechanism and directly call the methods in the class.

39 original articles published, 10 praised, 1232 visited
Private letter follow

Posted by osram on Thu, 06 Feb 2020 05:25:58 -0800