Annotation and reflection

I annotation

annotation(Annotation): Not the program itself, it can explain the program or be read by other programs.

Annotation format:@Note name, you can also add some parameters, such as:@SuppressWarnings(value="unchecked")

1. Built in annotation

Three commonly used built-in annotations:
① @Override : Override method. If it is found that its parent class or the referenced interface does not have this method, a compilation error will be reported. You can only modify methods.
② @Deprecated : Mark obsolete methods. The marked content is no longer recommended. You can modify methods, attributes, and classes.
③ @SuppressWarnings : Let the compiler"What it marks"Some warnings remain silent. You can modify classes and methods.

2. Meta annotation

The function of meta annotation is to annotate other annotations, that is, modify other annotations.
Four common meta annotations:
① @Retention : How to save this annotation is only in the code(SOURSE),Or incorporated class In the file(CLASS),
Or it can be accessed through reflection at runtime(RUNTIME). as@Retention(RetentionPolicy.SOURCE). 
	SOURSE<CLASS<RUNTIME
② @Documented : Mark that these annotations will be included in the user document(JavaDoc)Yes.
③ @Inherited : The tag subclass can inherit the annotation of the parent class.
④ @Target : Mark the scope of use of this annotation. as@Target(value=ElementType.METHOD). 
	TYPE Means that it can be marked"Class, interface (including annotation type) or enumeration declaration". 
	FIELD Means that it can be marked"Field declaration". 
	METHOD Means that it can be marked"method". 
	PARAMETER Means that it can be marked"parameter". 
	CONSTRUCTOR Means that it can be marked"Construction method". 
	LOCAL_VARIABLE Means that it can be marked"local variable". 

3. User defined annotation

use@Interface Custom annotation, inherited automatically java.lang.annotation.Annotation Interface.
Each method actually declares a configuration parameter. The name of the method is the name of the parameter, and the return value type is the type of the parameter.
Can pass default To declare the default value of the parameter
 If there is only one parameter member, the parameter name is generally declared as value
 Annotation element must have a value

Example of custom annotation:

public class Demo1DefineAnnotation {
    @MyAnnotation1(name = "Zhang San") // Each parameter must be assigned a value if it has no default value
    public void test1() {}

    @MyAnnotation2("Zhang San") // When there is only one parameter in the annotation and the parameter name is value, the parameter name can be omitted when writing
    public void test2(){}
}

@Inherited // Indicates that the subclass of the class modified by this annotation can inherit the annotation of the parent class
@Documented // Indicates that annotations can be saved in JavaDoc
@Target({ElementType.TYPE,ElementType.METHOD}) // Indicates that this annotation MyAnnotation1 can modify classes and methods
@Retention(RetentionPolicy.RUNTIME) // Indicates that this annotation MyAnnotation1 can be saved to the program runtime
@interface MyAnnotation1{  // Custom annotation
    String name(); // Annotation parameter, not method
    int age() default 0; // Set the default value of age to 0
}

@interface MyAnnotation2{  // Custom annotation
    String value(); // When there is only one parameter member, the parameter name is generally declared as value
}

II reflex

Reflection is the key to Java being regarded as a dynamic language. The reflection mechanism allows the program to obtain 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.

After loading the Class, an object of constant Class type (Class) is generated in the method area of heap memory (a Class has only one Class object), and this object contains complete Class structure information. We can see the structure of the Class through this object. This object is like a mirror. We can see the structure of the Class through this mirror, so we vividly call it reflection.

Class object is the root of Reflection. For any class you want to dynamically load and run, you have to obtain the corresponding class object first.

1. Method of obtaining Class object:

① Obtained by object: Class C1 = person getClass()
② Obtained by forname: class C2 = class forName(“Annotation.Student”)
③ Pass the class name Class: class C3 = student class
④ Type attribute of wrapper class through basic built-in type: class C4 = integer TYPE

// How to get the Class object
public class TestReflection {
    public static void main(String[] args) throws ClassNotFoundException {
        Student student = new Student();

        // Method 1: obtain through object
        Class c1 = student.getClass();
        System.out.println(c1+"\t"+c1.hashCode());

        //Party 12: forName obtained
        Class c2 = Class.forName("Annotation.Student");
        System.out.println(c2+"\t"+c2.hashCode());

        //Method 3: pass the class name Class get
        Class c3 = Student.class;
        System.out.println(c3+"\t"+c3.hashCode());

        //Method 4: packing classes of basic built-in types have a Type attribute
        Class c4 = Integer.TYPE;
        System.out.println(c4);
    }
}

class Student {}

result:

class Annotation.Student	460141958
class Annotation.Student	460141958
class Annotation.Student	460141958
int
There is only one in the same class Class object

2. Common methods of class:

static Class forName(String name): Returns the specified class name name of Class object
Object newInstance(): Return a Class Object instance
String getName(): Return to this Class The name of the class represented by the object(Package name+Class name)
String getSimpleName(): Return to this Class The name of the class represented by the object(Class name)
Class getSuperClass(): Return to current Class Of the parent class of the object Class object
Class[] getInterfaces(): Get current Class Object implemented interface
ClassLoader getClassLoader(): Gets the class loader for this class
Constructor[] getConstructors(): Get the object array of all constructors of this class
Method getMethod(String name, Class<?>... parameterTypes): Returns the name of the object with the specified name and parameter type public Method object(Including the of inheriting the parent class, but excluding the constructor)
Method[] getMethods(): Get all in the class public method(Including the of inheriting the parent class, but excluding the constructor)
Method getDeclaredMethod(String name, Class<?>... parameterTypes): Returns the method object of the specified name and parameter type object of this class(Inheritance and construction methods are not included)
Method[] getDeclaredMethods(): Get all methods of this class(And constructors that inherit from the parent class are not included)
Field getField(String name): Returns the property specified in this class(Including inherited),This property must be public
Field[] getFields(): Returns all the data in this class(Including inherited)Declared attribute object array, this field must be public
Field getDeclaredField(String name): Returns the property specified in this class(Excluding inherited)
Field[] getDeclaredFields(): Returns all the data in this class(Excluding inherited)Object array of declared properties
// Common methods of Class object
public class Demo4Reflection {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("Annotation.Teacher"); //Get Class object

        // Get the name of the class
        System.out.println(c1.getName()); // Annotation.Teacher
        System.out.println(c1.getSimpleName()); // Teacher
        System.out.println("================================");

        // Get the properties of the class
        System.out.println(c1.getField("name")); // Gets the specified public property
        System.out.println("---------------------------------");
        Field[] fields = c1.getFields(); // Get all public properties including inheritance
        for (Field field:fields) {
            System.out.println(field+"\t");
        }
        System.out.println("---------------------------------");
        System.out.println(c1.getDeclaredField("age")); // Gets the property of the specified declaration
        System.out.println("---------------------------------");
        fields = c1.getDeclaredFields(); // Get all properties excluding inheritance
        for (Field field:fields) {
            System.out.println(field);
        }
        System.out.println("================================");

        // Method to get class
        System.out.println(c1.getMethod("setName",String.class)); // Gets the method of the object with the specified name and parameter type, including the inherited
        System.out.println("---------------------------------");
        Method[] methods = c1.getDeclaredMethods(); // Get all methods excluding inheritance
        for (Method method:methods) {
            System.out.println(method);
        }
        System.out.println("================================");

        //Gets the constructor of the class
        Constructor[] constructors = c1.getConstructors(); // Get all constructors of this class
        for (Constructor constructor:constructors) {
            System.out.println(constructor);
        }
        System.out.println("---------------------------------");
        constructors = c1.getDeclaredConstructors(); // Get all constructors of this class
        for (Constructor constructor:constructors) {
            System.out.println(constructor);
        }
        System.out.println("---------------------------------");
        // Gets the specified constructor
        System.out.println(c1.getConstructor(String.class,int.class,int.class,String.class));
    }
}
class Person{
    public String name;
    private int id;

    public Person() {
    }
    public Person(String name, int id) {
        this.name = name;
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}
class Teacher extends Person {
    private int age;
    String sex;

    public Teacher() {
    }
    public Teacher(String name, int id, int age, String sex) {
        super(name, id);
        this.age = age;
        this.sex = sex;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}

result:

Annotation.Teacher
Teacher
================================
public java.lang.String Annotation.Person.name
---------------------------------
public java.lang.String Annotation.Person.name	
---------------------------------
private int Annotation.Teacher.age
---------------------------------
private int Annotation.Teacher.age
java.lang.String Annotation.Teacher.sex
================================
public void Annotation.Person.setName(java.lang.String)
---------------------------------
public int Annotation.Teacher.getAge()
public java.lang.String Annotation.Teacher.getSex()
public void Annotation.Teacher.setSex(java.lang.String)
public void Annotation.Teacher.setAge(int)
================================
public Annotation.Teacher()
public Annotation.Teacher(java.lang.String,int,int,java.lang.String)
---------------------------------
public Annotation.Teacher()
public Annotation.Teacher(java.lang.String,int,int,java.lang.String)
---------------------------------
public Annotation.Teacher(java.lang.String,int,int,java.lang.String)

3. Which types have Class objects

class Class interface Interface[]Array enum Enumeration annotation Annotation, basic data type void etc.
public class TestReflection {
    public static void main(String[] args) {
        Class c1 = Object.class; // class
        Class c2 = Comparable.class; // Interface
        Class c3 = String[].class; // One dimensional array
        Class c4 = int[][].class; // Two dimensional array
        Class c5 = Override.class; // annotation
        Class c6 = ElementType.class; // enumeration
        Class c7 = Integer.class; // Basic data type
        Class c8 = void.class; // void
        Class c9 = Class.class; // Class

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);

        int[] a = new int[10];
        int[] b = new int[5];
        // As long as the element type and dimension are consistent, it is the same Class
        System.out.println(a.getClass().hashCode()+" "+b.getClass().hashCode());
    }
}

result:

class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
460141958 460141958

4. Class loading process

① Compilation: the code is first compiled into a binary bytecode file (. class file)
② Load: load the bytecode content of the class file into memory, convert the static data into the runtime data structure of the method area, and then generate a class object representing this class
③ Link: the process of merging the binary code of Java classes into the running state of the JVM

  • Verification: ensure that the loaded class information complies with the JVM specification and there are no security problems
  • Preparation: allocate memory for class variable (static) and set the default initial value of class variable
  • Resolution: replace the symbolic reference (constant name) in the virtual machine constant pool with the direct reference (address)

④ Initialization: the process of executing the class constructor method. The class constructor method is generated by the combination of the assignment action of all class variables (static) in the class automatically collected during compilation and the statement of static code block (the class constructor constructs class information, not the constructor of this class object). When initializing a class, if it is found that its parent class has not been initialized, its parent class needs to be initialized first.

5. Class loader

The function of class loader is to load the class into memory, that is, load the bytecode content of class file into memory, convert the static data into the runtime data structure of method area, and then generate a class object representing this class.

There are three types of class loaders:

  • Bootstrap classloader: it is the class loader of the JVM. It is responsible for the core library of the Java platform and is used to load the core class library. It cannot be obtained directly
  • Extension classloader:
  • System classloader: the most commonly used loader
    Bootstap Classloader > Extension Classloader > System Classloader
// Class loader
public class ClassLoader {
    public static void main(String[] args) throws ClassNotFoundException {
        // Get system class loader
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

        // Get the parent class loader of the system class loader -- > extended class loader
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);

        // Get the parent class loader -- > root loader of the extended class loader
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1); // Cannot get directly, output null

        // Test which class loader loads the current class
        ClassLoader classLoader = Class.forName("Annotation.ClassLoader").getClassLoader();
        System.out.println(classLoader);

        // Test which loader loads the JDK built-in classes
        classLoader = Class.forName("java.lang.Object").getClassLoader(); // Root loader
        System.out.println(classLoader);
    }
}

result:

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1b6d3586
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
	Parental delegation mechanism:
When a class is to be loaded, it will first System ClassLoader Check whether it has been loaded. If so, there is no need to load it again.
If not, you will get the parent loader. Similarly, the parent class will first check whether it has been loaded. If not, go up.
Notice this recursive process until you reach the Bootstrap classLoader Before, they were checking whether they had been loaded, and did not choose to load them themselves.
until BootstrapClassLoader,There is no parent loader, so I start to think about whether I can load it.
If you can't load, you will sink to the sub loader to load until the bottom. If there is no loader to load, it will be thrown ClassNotFoundException. 

Generally, custom classes are created by System ClassLoader load

6. What can a Class object do

① Dynamically create objects and call methods and properties through reflection

// Create objects dynamically through reflection
// Invoke methods and properties through reflection
public class Demo7 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class c1 = Class.forName("Annotation.User"); // Get Class object

        // Create an instance object through reflection
        User user = (User) c1.newInstance(); // Equivalent to calling a parameterless constructor
        System.out.println(user.toString());

        // Creating instance objects through constructors
        Constructor constructor = c1.getDeclaredConstructor(int.class,String.class,int.class);
        user = (User) constructor.newInstance(10101,"Zhang San",18);
        System.out.println(user.toString());

        // Call method through reflection
        Method setName = c1.getDeclaredMethod("setName", String.class); // Get the specified method setName of this class
        setName.invoke(user,"Li Si"); // invoke: Activate
        System.out.println(user);

        // Operation properties by reflection
        Field name = c1.getDeclaredField("name");
        // You cannot directly operate the private attribute. You need to turn off the security detection of the program
        name.setAccessible(true); // Turn off security detection
        name.set(user,"Wang Wu");  // Equivalent to user Name = "Wang Wu"
        System.out.println(user.getName());
    }
}
class User{
    private int id;
    private String name;
    private int age;

    public User() {
    }
    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{id="+this.id+",name="+this.name+",age="+this.age+"}";
    }
}

result:

User{id=0,name=null,age=0}
User{id=10101,name=Zhang San,age=18}
User{id=10101,name=Li Si,age=18}
Wang Wu
Method,Field,Constructor All objects have setAccessible()Method to enable and disable access security checks
 Close safety check setAccessible(true)It can improve the efficiency of reflection execution

② Get annotation information

// Get annotation information through reflection
public class Demo10 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("Annotation.User2");

        //Get annotations through reflection
        Annotation[] annotations = c1.getAnnotations(); // Get all comments
        for (Annotation annotation:annotations) {
            System.out.println(annotation);
        }

        //Gets the parameter value of the annotation
        ClassAnnotation classAnnotation = (ClassAnnotation) c1.getAnnotation(ClassAnnotation.class); // Gets the specified annotation
        String value = classAnnotation.value();
        System.out.println(value);

        //Gets the annotation for the specified attribute
        Field id = c1.getDeclaredField("id"); // Gets the specified property
        FieldAnnotation fieldAnnotation = id.getAnnotation(FieldAnnotation.class);
        System.out.println(fieldAnnotation);
        System.out.println(fieldAnnotation.name());
        System.out.println(fieldAnnotation.type());
        System.out.println(fieldAnnotation.Length());
    }
}

@ClassAnnotation("User2")
class User2{
    @FieldAnnotation(name = "id",type = "int",Length = 10)
    private int id;
    @FieldAnnotation(name = "name",type = "String",Length = 5)
    private String name;
    @FieldAnnotation(name = "age",type = "int",Length = 10)
    private int age;

    public User2() {
    }
    public User2(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User2{id="+this.id+",name="+this.name+",age="+this.age+"}";
    }
}

// Class annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ClassAnnotation{ // Custom annotation
    String value(); // parameter
}

// Attribute annotation
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAnnotation{
    String name(); // Parameter: attribute name
    String type(); // Parameters: attribute types
    int Length(); // Parameters: attribute length
}

result:

@Annotation.ClassAnnotation(value=User2)
User2
@Annotation.FieldAnnotation(name=id, type=int, Length=10)
id
int
10

Tags: Java reflection Annotation

Posted by Dvector on Sat, 16 Apr 2022 03:25:19 +0930