Notes on annotation and reflection

Annotation and reflection

annotation

What is annotation

Annotation is a technology introduced by JDK5

Annotation is to explain the procedure

What's the difference between annotation and annotation

Annotations are explained to programs, and annotations are explained to people

Format of annotation:

Annotations exist in the code as "@ annotation name". You can also add parameter values, such as @ SuppressWarning (value = "unchecked")

Where can annotations be used

It can be used in package, class, method, field, etc., which is equivalent to auxiliary functions. We can access these metadata through reflection mechanism programming

Built in annotation

The built-in annotation is the annotation provided by the program

Three commonly used built-in annotations:

  • @Override

    Represents overriding a method declaration in a superclass

  • @Deprecated

    Indicates abandoned, not recommended

  • @SuppressWarnings

    Indicates that the warning message is ignored

parameterexplain
depreciationWarning that an obsolete class or method was used
uncheckedWarning when an unchecked transformation is performed, such as: no generics are specified when using a collection
fallthroughcase penetration occurs when used in a switch statement
pathThere is a warning that the path does not exist in the classpath and source file path
serialWarning when a serialVersionUID definition is missing on a serialized class
finallyWarning when any finally clause cannot be completed
allWarnings about all of the above

In the above table are some parameters of @ suppressWarnings annotation, which can be used as needed

@suppressWarnings("finally")

@suppressWarnings(value={"unchecked","path"})

Meta annotation

Function of meta annotation:

The function of meta annotation is to annotate other annotations. Four standard meta annotation types are defined in java, which are used to describe the types of other annotations

These types are in java.lang.annotation:

  • @Target: used to describe the scope of use of annotations, such as classes and methods
  • @Retention: indicates the level at which the annotation information needs to be saved. It is used to describe the annotation life cycle, generally in Runtime
  • @Document: note that the annotation will be included in the javadoc
  • @Inherited: indicates that the subclass can inherit the annotation in the parent class
package com.annotation.Demo;
import com.sun.istack.internal.Interned;
import java.lang.annotation.*;
/**
 * Meta annotation
 */
public class AnnotationDemo1 {
    //    Annotation can display assignment. If there is no default value, we must assign a value to the annotation
//    For example, in annotation 2 below
    //    If you don't assign a value, it will be red
    @annotation2(age = 22)
    public void test2() {
    }
    //    There is a default value in the annotation. It does not assign a value and does not affect the operation and compilation of the program
    @annotation3(age = 11)
    public void test3() {
    }
    //When there is only one parameter, you can directly use value instead of other names
    @annotation1(value = "11", age = 11,cource = 11.1)
    public void test() {
    }
    @annotation
    public void test4(){
    }
}
@Target({ElementType.TYPE, ElementType.METHOD})
@interface annotation2 {
    int age();
}
//Annotation parameters: can'shu'lei'can'shu'lei'xt({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface annotation1 {
    String value();
    int age();
    double cource();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface annotation3 {
    //    String name() default "Xiao Ming"; The default value is followed by default and the default value
    String name() default "Xiao Hong";
    int age();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface annotation{
    //The default value is "" 0 "". ""
    String name() default "";
    int age() default 0;
}

analysis:

  • When @ interface customizes annotations, it automatically inherits the java.lang.annotation.Annotation interface
  • @Interface is used to declare an annotation. Format: public @interface annotation name (custom content)
  • Each method actually declares a configuration parameter
  • The name of the method is the name of the parameter
  • The return value type is the type of the parameter (the return value can only be the basic type Class, String, enum, etc.)
  • You can declare the default value of the parameter through default
  • When there is only one parameter member, the general parameter name is value
  • The annotation element must have a value. When we customize the annotation element, we often use an empty string with 0 as the default value

reflex

Reflection mechanism

java Reflection

  • Reflection: it is the key to java being regarded as a quasi dynamic language. Reflection mechanism refers to that the program obtains the internal information of any class with the help of Reflection API during execution, and can directly operate the internal properties and methods of any object

Get class

//The first method is implemented through the static method of Class - forName()
class1 = Class.forName("com.xxxx.User");
//The second way is through the class attribute of the class
class1 = Object.class;
//The third way is through the object getClass method
Object obj = new Object();
Class<?> class1 = obj.getClass();
  • After the Class is loaded, a Class object will be generated in the method area of heap memory. A Class has only one Class object, which contains complete Class structure information. We can see the structure of the Class through this object. This object is like a mirror clear lake. Through the lake, we can see the internal structure of the Class, so we call it "reflection".

To understand it with plug-ins in the game is: when the game is in progress, starting plug-ins is to create class objects during operation.

Normal method: you need to import the "package class" name > > > instantiate through the new method > > > get the instantiated object

Reflection method: instantiate Object > > > getclass() > > > get the complete "package class" name

Basic operation of reflection

Class aClass = Class.forName("com.xxxx.User");
//Get full class name
String name = aClass.getName();
//Get a simple class name
String simpleName = aClass.getSimpleName();
//Get the public field of the class according to the field name
Field field = aClass.getField("age");
//Gets the method of the class according to the method name
Method declaredMethod = aClass.getDeclaredMethod("getName");

Class instantiation

Class aClass = Class.forName("com.xxxx.User");
//It is directly instantiated through the class class and uses the parameterless constructor of the User class
User user = (User) aClass.newInstance();

Call the method of the class

//First, you need to obtain the Method object corresponding to the Method
Method method = class1.getDeclaredMethod("setAge", int.class);
//Calls the specified function and passes arguments
method.invoke(obj, 28);

Research and application of Java reflection mechanism

Functions provided by Java reflection mechanism:

  • Determine the class of any object at run time
  • Construct an object of any class at run time
  • Judge the member variables and methods of any class at run time
  • Call the member variables and methods of any object at run time
  • Get generic information at run time
  • Processing annotations at run time
  • Generate dynamic proxy

Class class

Class is very important for reflection. The information obtained by an object after reflection: the attributes, methods and constructors of a class, which interfaces a class implements and which classes it inherits. For each class, JRE reserves an object of constant class type. A class object contains class, interface, enum and annotation of a specific structure , primitive type, void, [] and other related information

  • Class itself is a class
  • Class objects can only be created by the system
  • A loaded Class has only one Class instance in the JVM
  • A class object corresponds to a. Class file loaded into the JVM
  • All loaded structures in a Class can be completely obtained through Class
  • Class is the root of Reflection. For any class you want to dynamically load and run, you have to obtain the corresponding class object first
Method nameFunction description
static ClassforName(String name)Returns the Class object with the specified Class name
Object newInstance()Call the default constructor to return an instance of the Class object
getName()Returns the name of the entity (Class, interface, array Class or void) represented by this Class object
Class getSuperClass()Returns the Class object of the parent Class of the current Class object
Class[] getInterfaces()Gets the interface of the current Class object
ClassLoader getClassLoader()Returns the class loader for this class
Constructor[] getConstructors()Returns an array containing some constructor objects
Method getMethod(String name,Class... T)Returns a Method object whose formal parameter type is paramType
Field[] getDeclaredFields()Returns an array of Field objects

Java Memory Analysis

Java Memory

  • Heap:
    • new objects and arrays
    • It can be shared by all threads without storing other object references
  • Stack:
    • Store the basic variable type (including the specific value of this basic type)
    • The variable of the reference object (the specific address of the reference in the heap will be stored)
  • Method area:
    • Can be shared by all threads
    • Contains all class and static variables

Class loading process

When a program actively uses a class, if the class has not been loaded into memory, the system will initialize the class through the following three steps

  • Class loading: read the class file of the class into memory and create a java.lang.Class object for it. This process is completed by the class loader
  • Class Link: merge the binary data of the class into the JRE
  • Class initialization: the JVM is responsible for initializing the class

Active reference of class:

  • When the virtual machine starts, initialize the class where the main method is located first
  • new is an object of a class
  • Call static members (except final constants) and static methods of the class
  • Use the methods of the java.lang.reflect package to make reflection calls to the class
  • When initializing a class, if the parent class is not initialized, the parent class will be initialized first

Passive reference to class:

  • When accessing a static code block, only the class that actually declares the code block will be initialized. For example, when the static variable of the parent class is referenced through the subclass, the subclass will not be initialized
  • Defining a class reference through an array does not trigger the initialization of this class
  • References to constants also do not trigger initialization
public class Demo5 {
    static {
        System.out.println("main Class is loaded");
    }
    public static void main(String[] args) throws ClassNotFoundException {
//        Active reference: load the parent class first and then the child class
//        Son son=new Son();
//        Reflection produces an active reference
//        Class.forName("com.reflection.Demo.Demo5");
//        A reference constant will not trigger the referenced method of a class, and calling a parent constant through a subclass will not trigger initialization
//          System.out.println(Son.b);
            System.out.println(Son.m);
    }
}
class Father{
    static int b=2;
    static{
        System.out.println("The parent class is loaded");
    }
}
class Son extends Father{
    static int c=3;
    static {
        System.out.println("Subclass loaded");
    }
        static final int m=1;
}

Role of class loader

Function: load the class file into memory, convert these static data into the runtime data structure of the method area, and then generate a java.lang.Class object representing this class in the heap as the access entry for the class data in the method area.

Class cache: the standard JavaSE class loader can find classes as required, but once a class is loaded into the class loader, it will remain loaded for a period of time (CACHE). The gc garbage collection mechanism can recycle the cached class objects

public class Demo1 {
    public Demo1() throws ClassNotFoundException {
    }
    public static void main(String[] args) throws ClassNotFoundException {
        //    Get system class loader
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        //sun.misc.Launcher$AppClassLoader@14dad5dc
//        Get parent class loader of system class loader > > extension loader
        ClassLoader sysParent = systemClassLoader.getParent();
        System.out.println(sysParent);
//        sun.misc.Launcher$ExtClassLoader@677327b6
//        Gets the parent class loader > > root loader of the extension class loader
        ClassLoader extParent = sysParent.getParent();
        System.out.println("ext:" + extParent);
//        null
//        Test which loader loads the current class
        ClassLoader classParent = Class.forName("com.ClassLoader.Demo.Demo1").getClassLoader();
        System.out.println("class:" + classParent);
//        class:sun.misc.Launcher$AppClassLoader@14dad5dc
//        Test who loaded the JDK built-in class
        ClassLoader jdkParent = Class.forName("java.lang.Object").getClassLoader();
        System.out.println("jdk:" + jdkParent);
//        jdk:null
//        Get the system classloader load path
        System.out.println(System.getProperty("java.class.path"));
//         . . . 
    }
}

Get class information

package com.ClassLoader.Demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
//        Class c1=Class.forName("com.ClassLoader.Demo.User");
        User user=new User();
        Class c1=user.getClass();
        System.out.println(c1.getSimpleName());
        System.out.println("*************************");
//        Get class name + detailed path
        System.out.println(c1.getName());
//        Get the name of the class
        System.out.println(c1.getSimpleName());
//        Get the properties of this class
        Field[] fields=c1.getFields();      //The public attribute can be found
        fields=c1.getDeclaredFields();      //All attributes can be found
        for (Field field:fields) {
            System.out.println(field);
        }
        Field name=c1.getDeclaredField("name");
        System.out.println(name);
        System.out.println("*************************");
//        Get the method of the class
        Method[] methods=c1.getDeclaredMethods();
        for (Method method : methods) {     //Get all methods of this class and its parent class
            System.out.println("getDeclaredMethods:"+method);
        }
        System.out.println("*************************");
        Method[] methods1=c1.getMethods();
        for (Method method : methods1) {        //Get all methods of this class
            System.out.println("getMethods:"+method);
        }
        System.out.println("*************************");
//        Gets the specified method
//        heavy load
        Method getName=c1.getMethod("getName",null);
        Method setName=c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);
        System.out.println("*************************");
//        Gets the constructor of the specified instance object
        Constructor[] constructors=c1.getConstructors();//Get public method
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        Constructor[] constructors1=c1.getDeclaredConstructors();//Get all methods
        for (Constructor constructor : constructors1) {
            System.out.println(constructor);
        }
        System.out.println("*************************");
        //Gets the specified constructor
        Constructor declareConstructor=c1.getDeclaredConstructor(String.class,int.class,double.class);
        System.out.println(declareConstructor);
    }
}

Class loading and ClassLoader understanding

What can you do with a Class object?

Create Class object: call newInstance () method of Class object

  • Class must have a parameterless constructor
  • The constructor of the class needs sufficient access rights
   //Get Class object
        Class aClass=Class.forName("com.ClassLoader.Demo.User");
//        Construct an object
        Essentially, a parameterless constructor is called
        User user1=(User) aClass.newInstance();
        System.out.println(user1);
//Result: y name isnull,my id is 0i got 0.0points
//        You can not only create objects with a parameterless constructor, but also with a parameterless constructor
        Constructor constructor=aClass.getDeclaredConstructor(String.class,int.class,double.class);
        User user2=(User) constructor.newInstance("zhangsan",1,99.9);//The number of parameters must be consistent, otherwise an exception occurs
        System.out.println(user2);
//Running result: my name is Du, my id is 1i got 99.9points

If you do not know the number and type of parameters of the Class object, you can obtain information through Field

        //Note: if you don't know how many variables the Class object has, you can get information through Field
        Field[] fields=aClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

Call normal methods through reflection

//        Call normal methods through reflection
        User user= (User) aClass.newInstance();
//        Get a method by reflection
        Method setName=aClass.getDeclaredMethod("setName", String.class);
//        inoke means active
        setName.invoke(user,"zhangsan");
        System.out.println(user.getName());

Operation properties by reflection

//        By reflecting operation attributes, private attributes cannot be directly operated. They can be turned off by closing the security detection of the program
        User user4=(User) aClass.newInstance();
        Field name=aClass.getDeclaredField("name");
        name.setAccessible(true);       //Can pass. The variables modified by private have a security protection mechanism,
        name.set(user4,"zhangsan");
        System.out.println(user4.getName());
    }

Call the specified method

Through reflection, the Method in the class is called and completed through the Method class

  • Obtain a Method object through the getMethod(String name,Class... parameterTypes) Method of Class class, and set the parameter type required for this Method operation.
  • Use Object invoke (Object obj,Object []) to call and pass the parameter information of the ovj object to be set to the method

  • If the return value of the Object object method or the original method has no return value, the run result returns null
  • If the original method is static, the formal parameter Object can be null
  • If the original method parameter list is empty, Object args is null
  • If the original method is declared private private, you need to call the setAccessible(true) of the method object before invoke(), so that you can make a violent reflection.

About setAccessible(), its function is to start and disable the switch of security check. When the Boolean value is true, the java program cancels the access check, and when false, starts the access check.

  • It improves the efficiency of reflection. If reflection must be used in code, this method is essential
  • Can make inaccessible private members be forcibly accessed

Full Demo

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo3 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //Get Class object
        Class aClass=Class.forName("com.ClassLoader.Demo.User");
//        Construct an object
//        Essentially, a parameterless constructor is called
        User user1=(User) aClass.newInstance();
        System.out.println(user1);
//Result: y name isnull,my id is 0i got 0.0points
//        You can not only create objects with a parameterless constructor, but also with a parameterless constructor
        Constructor constructor=aClass.getDeclaredConstructor(String.class,int.class,double.class);
        User user2=(User) constructor.newInstance("zhangsan",1,99.9);//The number of parameters must be aligned with that of getdeclaraedconstructor()
        System.out.println(user2);
//Running result: my name iszhangsan,my id is 1i got 99.9points
        //Note: if you don't know how many variables the Class object has, you can get information through Field
//        Field[] fields=aClass.getDeclaredFields();
//        for (Field field : fields) {
//            System.out.println(field);
//        }
//        Call normal methods through reflection
        User user= (User) aClass.newInstance();
//        Get a method by reflection
        Method setName=aClass.getDeclaredMethod("setName", String.class);
//        inoke means active
        setName.invoke(user,"zhangsan");
        System.out.println(user.getName());
//        By reflecting operation attributes, private attributes cannot be directly operated. They can be turned off by closing the security detection of the program
        User user4=(User) aClass.newInstance();
        Field name=aClass.getDeclaredField("name");
        name.setAccessible(true);       //Can pass. The variables modified by private have a security protection mechanism,
        name.set(user4,"zhangsan");
        System.out.println(user4.getName());
    }
}

Performance comparison

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo4 {
    //    Normal execution
    public static void test1(){
        User user=new User();
        long startTime=System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long endTime=System.currentTimeMillis();
        System.out.println("1 billion times in ordinary way"+(endTime-startTime)+"ms");
    }
    //    Reflection mode execution
    public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user=new User();
        Class c1=user.getClass();
        Method getName=c1.getDeclaredMethod("getName",null);
        long startTime=System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user,null);
        }
        long endTime=System.currentTimeMillis();
        System.out.println("1 billion times in reflection mode"+(endTime-startTime)+"ms");
    }
//        Turn off detection reflection mode execution
    public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user=new User();
        Class c1=user.getClass();
        Method getName=c1.getDeclaredMethod("getName",null);
        getName.setAccessible(true);
        long startTime=System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user,null);
        }
        long endTime=System.currentTimeMillis();
        System.out.println("Turn off the detection reflection mode for 1 billion times"+(endTime-startTime)+"ms");
    }
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test1();
        test2();
        test3();
    }
}

Get annotation information through reflection

package com.AnnotationReflect.Demo;
import java.lang.annotation.*;
import java.lang.reflect.Field;

public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
    Class c1=Class.forName("com.AnnotationReflect.Demo.Student1");
//    Get annotations through reflection
    Annotation[] annotations=c1.getAnnotations();
    for (Annotation annotation : annotations) {
        System.out.println(annotation);
    }
//    Get the value of annotation value
    TableLong tableLong=(TableLong)c1.getAnnotation(TableLong.class);
    String value=tableLong.value();
    System.out.println(value);
//    Gets the annotation specified by the class
    Field field=c1.getDeclaredField("name");
    FiledStudent annotation=field.getAnnotation(FiledStudent.class);
    System.out.println(annotation.columName());
    System.out.println(annotation.type());
    System.out.println(annotation.length());
}
}
@TableLong("studentinfo")
class Student1{
    @FiledStudent(columName = "Sno",type="int",length = 10)
    private int id;
    @FiledStudent(columName = "Sname",type="int",length = 10)
    private String  name;
    @FiledStudent(columName = "Sex",type="int",length = 10)
    private String sex;
    public Student1(int id, String name, String sex) {
        this.id = id;
        this.name = name;
        this.sex = sex;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FiledStudent{
    String columName();
    String type();
    int length();
}
//Annotation of class name
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableLong{
    String value();
}

Keywords: Java reflection JavaSE

Added by anurag2003 on Fri, 19 Nov 2021 20:51:10 +0200