1. Notes
1.1 introduction to notes
Annotation is a new technology introduced by JDK 5.0. Its main functions are:
- Explain the procedure and it is not a procedure itself (this function is the same as that of annotation);
- It can be read by other programs (such as compiler, etc.).
Annotation format: annotations exist in the code in the format of @ annotation name, and some parameter values can be added, such as @ SuppressWarnings(value = "unchecked").
Application scenario of Annotation: annotations can be attached to package, class, method and field, which is equivalent to adding additional auxiliary information and description information to these elements. Then we can program to access and use the data source provided by annotations through reflection mechanism.
1.2 built in notes
Built in annotations are some of the most commonly used annotations prepared for us by Java in advance:
- @Override: this annotation is defined in Java Lang. override is only applicable to modified methods, indicating that the declared method is a method in the overridden parent class.
- @Deprecated: this annotation is defined in Java Lang. deprecated can modify methods, attributes and classes, which means that programmers are not encouraged to apply such elements again, but it does not mean that they cannot be used; It is usually because the element is dangerous or there is a better substitute than the element, i.e. expired.
- @SuppressWarnings: this annotation is defined in Java Lang. SuppressWarnings is used to suppress the warning information during compilation, and the annotation needs to add parameters to be used correctly. These parameters are defined in advance. For example:
1. @SuppressWarnings(value = "all");
2. @SuppressWarnings(value = "unchecked");
3.@ Suppresswarnings (value = {"unchecked", "depreciation"}) and so on
1.3 yuan notes
Meta annotation is used to annotate other annotations, explain and specify user-defined annotations, that is, to help complete the definition of other annotations. Meta annotation in Java In lang.annotation package, four standard meta annotations are defined in Java:
- @Target: used to describe the scope of use of the annotation, that is, to define where the annotation can be used.
- @Retention: indicates the level at which the annotation information needs to be saved. It is used to describe the declaration cycle of the annotation (source code < compiled file < runtime).
- @Document: note that the annotation will be included in javadoc.
- @Inherited: indicates that the subclass can inherit the annotation in the parent class.
The following is the source code of the built-in annotation @ Deprecated, which uses multiple meta annotations:
/** * A program element annotated @Deprecated is one that programmers * are discouraged from using, typically because it is dangerous, * or because a better alternative exists. Compilers warn when a * deprecated program element is used or overridden in non-deprecated code. * * @author Neal Gafter * @since 1.5 * @jls 9.6.3.6 @Deprecated */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }
1.4 user defined annotation
The definition of annotation is very similar to our definition of interface. You only need to add the @ symbol in front of the interface keyword, that is, @ interface. The complete format is: public @interface annotation name {define annotation content}. The annotation is also the same as the interface. It can declare methods, but its function is very different from that of the interface:
- The method name is actually the parameter name of the annotation. The method is the parameter;
- The data type of the return value of the method is the data type required by the parameter, and can only be the basic data type;
- You can use the default keyword to set the default value for the parameter. Generally, you often use an empty string or 0 as the default value.. For example, String value() default "Korin"; Represents a string whose default value is korbin;
- If there is only one parameter member, the general parameter name is value, so you can omit the parameter name and give the value directly when using annotation;
- The annotation parameter must have a value. If there is a default value, you don't need to specify it explicitly. Otherwise, you must specify the value.
The following is a user-defined annotation for simple declaration:
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value() default ""; String[] names(); int id() default 0; }
2. Reflection mechanism
The above annotations are essentially used to store explanatory information and auxiliary information. In addition to some of Java's own annotations that can be recognized by the compiler, how should our custom annotations use this information? Isn't it meaningless to just declare but not use it? The answer is that you can do a lot of work by using annotations in combination with Java's reflection mechanism.
2.1 overview of java reflection mechanism
Concepts of dynamic language and static language:
- Dynamic language is a kind of language that can change its code structure when the code is running. For example, in the process of program running, new functions, objects and even code can be introduced, and existing functions can also be deleted or modified. Simply put, the code we write can dynamically change its structure and logic according to our needs. Now some major dynamic languages are: Object-C, c#, JavaScript, PHP and Python.
- Static language is opposite to dynamic language. In order to ensure the security of the program, the structure is not allowed to be changed when the program is running. The common static languages are Java, C and C + +.
Java is not a dynamic language, but Java can also be called "quasi dynamic language". It is the existence of reflection mechanism in Java that makes Java Dynamic and makes Java programming more flexible:
Reflection is the key that Java can be regarded as a dynamic language to a certain extent. Java's reflection mechanism allows programs to obtain the internal information of any class with the help of reflection API during running, and can directly operate the internal properties and methods of any object.
In the JVM virtual machine of Java, after loading each class in the program, an object of class type will be generated in the method area of heap memory. Class itself is a class in Java (java.lang.Class), and each custom class has only one class object; In fact, each class object corresponds to its corresponding class Class compiled file. This class object contains the complete data structure of this class in the JVM and provides the interface to access these data structures. Therefore, we can perform relevant operations on this class through this class object.
The following figure shows the normal way to create an instantiated object of a class through the full class name; The reflection method is the reverse. The class object of the object is obtained through the instantiated object name. This is the origin of the name of reflection mechanism.
Advantages and disadvantages of Java reflection mechanism:
- Advantages: it can dynamically create objects and compile, reflecting great flexibility.
- Disadvantages: reflection has an impact on performance. Because using reflection mechanism is equivalent to an interpretation operation, we can tell the JVM what we want it to do and it will meet our requirements. Such an operation is always slower than the direct execution of the program.
The key of reflection mechanism is: Class; In fact, reflection mechanism is the design soul of various Java frameworks that we will learn and use later~
2.2 get Class objects
In Java, there are many ways to obtain the Class object of a Class:
- If you know the specific class name, you can get the class object through the class attribute of the class. This method of obtaining class objects is the most safe and reliable, and the program performance is the highest.
- If the instance object of a Class is known, the Class object of its own Class can be obtained by calling the getClass() method of the instance object.
- If you know the full Class name of a Class and the Class is under the Class path, you can obtain the Class object of the Class through the static method forName() of the Class.
- The built-in basic data type can also obtain Class objects directly through the static member variable type, such as Class clazz = integer TYPE;.
So what types of Class objects are there in Java?
- Class: external class, member internal class, static internal class, local internal class and anonymous internal class.
- interface: interface
- []: array
- enum: Enumeration
- @interface: Annotation
- Basic data type
- void
2.2.1 class attribute of class
By default, each class in Java will have a class attribute, which stores all the structural information of the class. Calling this property returns the class object of this class.
The example customizes the User class, obtains the class object through the class attribute of the User class, and prints out the full package class name:
public class Main { public static void main(String[] args) { Class<User> clazz = User.class; System.out.println(clazz); /* Run result: class top korbin. reflection. User */ } } class User { private Long id; private String name; public Long getId() {return id; } public void setId(Long id) {this.id = id; } public String getName() {return name; } public void setName(String name) {this.name = name; } }
2.2.2 Object.getClass() method
The Object class in Java provides public final native class <? > GetClass () method obtains its class Object through Object instance; And this method will be inherited by all subclasses. In fact, the Object class is the parent class of all classes in Java. Even if there is no explicit declaration, the compiler will add it by default, so it is equivalent to that each class has this method.
Get its Class object directly through the getClass() method of the instance object, and print out the full package Class name:
public class Main { public static void main(String[] args) { User user = new User(); Class<? extends User> clazz = user.getClass(); System.out.println(clazz); /* Run result: class top korbin. reflection. User */ } }
2.2.3 Class.forName() method
The key Class of Java reflection mechanism: Class, which provides public static Class <? > Forname (string classname) static method, which takes the full Class name as the parameter of the method to obtain the Class object. If the passed string parameter is illegal, you need to catch an exception:
public class Main { public static void main(String[] args) { try { Class<?> clazz = Class.forName("top.korbin.reflection.User"); System.out.println(clazz); } catch (ClassNotFoundException e) { e.printStackTrace(); } /* Run result: class top korbin. reflection. User */ } }
Classloader class 2.3
Class loader is responsible for loading classes and generating corresponding class objects for them. Although we don't need to care about the class loading mechanism, we can better understand the operation of the program by understanding the class loading mechanism~
2.3.1 class loading process
Before understanding the class loading process, we must also have a basic understanding of the memory structure in the Java virtual machine:
When is the class loaded?
Generally speaking, class loading is only carried out when a class is actively called for the first time, that is, it is initialized only once. If a class has a parent class, it will load its parent class first, and then load itself. The JVM specifies the following six situations as active calls:
- An instance of a class is created (new operation, reflection, cloning, deserialization);
- Call the static method of the class;
- When using or assigning a value to the static attribute of the class / interface (this does not include the final constant and the constant expression determined at compile time);
- When calling some reflection methods in the API;
- Subclasses are initialized;
- Is set as the startup class when the JVM starts (the class with the main method).
The rest are passive calls, that is, the JVM will automatically load, such as final constants.
Loading process of Java classes in JVM virtual machine:
After understanding the above basic knowledge, for the class loading process, when the program actively uses a class, if the class has not been loaded into Java memory, that is, when the above active and passive calls are met, the JVM will initialize the class through the following three steps:
- Loading: this process is mainly completed by Classloader The bytecode content of the class file is loaded into the JVM memory method area, and the data of the class is converted into the runtime data structure corresponding to the method area, and then a java.xml file representing this class is generated Lang. class object.
- Linking: the process of merging the binary code of Java classes into the running environment state of the JVM.
- Verification: ensure that the loaded class information complies with the JVM specification and there is no security problem, that is, code syntax verification.
- Preparation: the stage of formally allocating memory for class member variables (excluding instance variables) and setting the default initial value. These memory will be allocated in the method area. This phase does not execute any code, but simply determines the initial value according to the variable type.
- Resolution: the process of replacing the symbolic reference (constant name) in the virtual machine constant pool with a direct reference (address), that is, the process of initializing the final constant.
- Initialization: at this stage, the JVM will actually execute code, including code blocks (static and non static), constructors, and explicit assignment of variables. The execution order of these codes follows the following two principles:
- If there is static modification, initialize static first, and then non static;
- The member variable is explicitly initialized first, then the code block is constructed for initialization, and finally the constructor is called for initialization.
The above figure shows that the test run outputs the values of static member variables in different places. Combined with the above class loading process, observe the initialization process of member variable values:
public class Main { public static void main(String[] args) throws ClassNotFoundException { System.out.println("stay main Output its directly in the main function num Value of static member variable:"+A.num); System.out.println("============================================="); new A(); System.out.println("stay main Create in main function A Class object, and then output its num Value of static member variable:"+A.num); } } class A { public static int num = 100; static { System.out.println("A Class"); System.out.println("A Class num The static variable value is:"+num); System.out.println("A Class num Assignment 300"); num = 300; } public A(){ System.out.println("A Class's parameterless constructor initialization"); System.out.println("A In the parameterless construction method of class num The static variable value is:"+num); System.out.println("A Class num Assignment 500"); num = 500; } }
2.3.2 classification and function of class loader
The function of the Class loader is to load the Class into the JVM memory. The JVM specification defines the following types of Class loaders:
- Bootstrap Classloader: written in C + +, 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 (such as String, System, etc.). The classes under jre/lib/rt.jar are core classes. This class loader cannot get directly.
- Extension Classloader: it is responsible for the jar package under jre/lib/ext directory or - D Java The jar in the directory specified by ext.dirs is packaged into the working library.
- System Classloader/AppClassLoader: responsible for java -classpath or - D Java class. The classes and jar s in the directory indicated by path are packaged into the working library. Is the most commonly used class loader.
public class Main { public static void main(String[] args) throws ClassNotFoundException { //Get system class loader ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); //Gets the parent class of the system class loader: extension class loader ClassLoader extensionClassLoader = systemClassLoader.getParent(); System.out.println(extensionClassLoader); //Get the parent class of extension class loader: boot class loader (cannot get, null) ClassLoader bootstrapClassLoader = extensionClassLoader.getParent(); System.out.println(bootstrapClassLoader); //Gets the class loader of the current class ClassLoader currentClassLoader = new Main().getClass().getClassLoader(); System.out.println(currentClassLoader); //Get the class loader of Object class built in JDK ClassLoader objectClassLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(objectClassLoader); } }
2.3 common methods of class objects
Serial number | Method name | Function description |
---|---|---|
1 | getName() | Returns the name of the class in String form. |
2 | newInstance() | Generate an instance of its corresponding Class according to a Class object, which calls the default constructor of this Class (no default parameterless constructor will report an error) |
3 | getClassLoader() | Returns the Class loader of the Class corresponding to the Class object. |
4 | getSuperClass() | Returns the Class object corresponding to the direct parent Class corresponding to a subclass |
5 | isArray() | Determine whether the Class object corresponds to an array object |
6 | getComponentType() | If the current Class represents an array, the Class object representing the array component is returned; otherwise, null is returned. |
7 | getConstructor(Class[]) | Returns the specified public constructor sub object of the Class represented by the current Class object. |
8 | getConstructors() | Returns an array of all public construction sub objects of the Class represented by the current Class object. |
9 | getDeclaredConstructor(Class[]) | Returns a specified construction sub object of the Class represented by the current Class object. |
10 | getDeclaredConstructors() | Returns an array of all described construction sub objects of the Class represented by the current Class object. |
11 | getDeclaredField(String) | Returns a specified domain object of the Class or interface represented by the current Class object. |
12 | getDeclaredFields() | Returns an array of all described domain objects of the Class or interface represented by the current Class object. |
13 | getDeclaredMethod(String, Class[]) | Returns a specified method object of the Class or interface represented by the current Class object. |
14 | getDeclaredMethods() | Returns an array of all the described methods of the Class or interface represented by the Class object. |
15 | getField(String) | Returns the specified public member domain object of the Class or interface represented by the current Class object. |
16 | getFields() | Returns an array of all accessible public domain objects of the Class or interface represented by the current Class object. |
17 | getInterfaces() | Returns the interface implemented by the class or interface represented by the current object. |
18 | getMethod(String, Class[]) | Returns the specified public member method object of the Class or interface represented by the current Class object. |
19 | getMethods() | Returns an array of all public member method objects of the Class or interface represented by the current Class object, including declared and inherited methods from the parent Class. |
20 | isInstance(Object) | This method is a dynamic equivalent method of instanceof operation in Java language. |
21 | isInterface() | Determines whether the specified Class object represents an interface type |
22 | isPrimitive() | Determines whether the specified Class object represents a Java base type. |
23 | newInstance() | Create a new instance of the class |
2.4 reflection dynamic acquisition of complete class structure
With the Class object, we can dynamically obtain the complete Class structure (member variables and methods, etc.) of a Class by calling the method of the Class object in the above question:
public class Main { public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException { //The simulation obtains an Object object that is transformed upward Object object = new User(10007L,"Korbin"); Class clazz = object.getClass(); //To get the structure of the class, please print out and view it yourself System.out.println(clazz.getName());//Get full class name System.out.println(clazz.getSimpleName());//Get a separate class name Field[] fields = clazz.getFields();//Gets all public properties of the class Field[] declaredFields = clazz.getDeclaredFields();//Get all properties of the class, including public and private properties Field name = clazz.getField("name");//Gets the object of the property through the specified property name Method[] methods = clazz.getMethods();//Gets all public methods of the current class and its parent class Method[] declaredMethods = clazz.getDeclaredMethods();//Get all methods of the current class, including public and private methods Method getName = clazz.getMethod("getName", null);//Gets the object of the method through the specified method name and method parameters Constructor[] constructors = clazz.getConstructors();//Get all public constructors of the class Constructor[] declaredConstructors = clazz.getDeclaredConstructors();//Get all construction methods of the class, including private and public construction methods Constructor constructor = clazz.getConstructor(Long.class, String.class);//Obtain the specified construction parameters through the construction parameters } }
2.5 reflection dynamic operation object instance
2.5.1 creating object instances
Now that we have Class objects, we can also dynamically create object examples of this Class directly through the newInstance() method, but we need to meet the following two conditions:
- Class must have a parameterless constructor
- The constructor of the class needs sufficient access rights. That is, it cannot be private.
Of course, classes without parameterless constructors can also create object instances. Just call the Constructor method getconstructor (Class... Parametertypes) described above through the Class object to pass in the Constructor parameter type, and then call the newInstance method through the Constructor object to pass in the parameter value to get the instantiated object of the Class.
public class Main { public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Class clazz = User.class;//Or according to Class Forname get Class object Object user = clazz.newInstance(); System.out.println(user); Constructor constructor = clazz.getConstructor(Long.class, String.class); User user1 = (User) constructor.newInstance(1007L,"Korbin"); System.out.println(user1); /*Operation results: User{id=null, name='null'} User{id=1007, name='Korbin'} */ } }
2.5.2 method of executing object instance
After dynamically obtaining the object instance of the class through the reflection mechanism, we can further call the method to execute the instance object. Through the method setnamemethod = clazz introduced above getDeclaredMethod("setName", String.class); Method gets the method object, and then invokes its invoke(); The value of the method and the parameter of the class are called, and the value of the method and the parameter of the class are implemented:
public class Main { public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Class clazz = User.class; User user = (User) clazz.newInstance(); System.out.println(user); Method setNameMethod = clazz.getDeclaredMethod("setName", String.class); setNameMethod.invoke(user,"Korbin111"); System.out.println(user); /* Operation results: User{id=null, name='null'} User{id=null, name='Korbin111'} */ } }
Note that if the called Method is a private private Method, it will not have sufficient permission to execute the Method and throw an IllegalAccessException exception. However, we can turn off the switch of access security check by calling the setAccessible(true) Method of Method before executing the Method.
2.5.3 member variables of operation object instances
After getting the instance object of the class through reflection, you can also use the Field name = clazz getDeclaredField("name"); Method operates on the properties (member variables) of the class. For example, the assignment of attributes can be realized by passing in the instance object and attribute value as parameters through the set() method of Field; The property value can be obtained by passing in the property name as a parameter through the get() method:
public class Main { public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException { Class clazz = User.class; Object user = clazz.newInstance(); System.out.println(user); Field name = clazz.getDeclaredField("name"); name.setAccessible(true);//Turn off the access security check switch name.set(user,"Korbin666"); System.out.println(name.get(user)); System.out.println(user); /* Operation results: User{id=null, name='null'} Korbin666 User{id=null, name='Korbin666'} */ } }
2.6 comparison and analysis of reflection and common mode performance
public class Main { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { test1(); test2(); test3(); } //Method of calling object in normal way public static void test1(){ User user = new User(); long startTime = System.currentTimeMillis(); //Perform 1 billion calls to object methods for (int i = 0; i < 1000000000; i++) { user.getName(); } long endTime = System.currentTimeMillis(); System.out.println("1 billion times of ordinary execution time:"+(endTime-startTime)+"ms"); } //Reflection mode call public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Object user = new User(); Class clazz = user.getClass(); Method getName = clazz.getDeclaredMethod("getName", null); long startTime = System.currentTimeMillis(); //Perform 1 billion calls to object methods for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("Execution time of reflection mode 1 billion times:"+(endTime-startTime)+"ms"); } //Called when reflection mode and security monitoring is turned off public static void test3() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { Object user = new User(); Class clazz = user.getClass(); Method getName = clazz.getDeclaredMethod("getName", null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); //Perform 1 billion calls to object methods for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("Reflect and turn off the safety monitoring mode for 1 billion times time:"+(endTime-startTime)+"ms"); } }
Operation results:
If there are too many reflection calls, it is recommended to turn off the access security check switch to improve the efficiency of program execution~
2.7 reflection operation generics
Generics in Java use the mechanism of generic erasure to introduce generics. Generics in Java are only used by the compiler javac to ensure the security of data and avoid the problems caused by forced type conversion. Therefore, once compilation is completed, all types related to generics will be operated.
In order to operate generics through reflection, Java has added parameterizedtype, GenericArrayType, TypeVariable and WildcardType to represent types that cannot be classified as Class types but have the same name as the original type.
- Parameterizedtype: represents a parameterized type, such as collection < string >;
- GenericArrayType: indicates that an element type is a parameterized type or an array type of type variable;
- TypeVariable: it is the public parent interface of various types of variables;
- WildcardType: represents a wildcard type expression.
Example: get generics through reflection mechanism:
public class Main { public static void main(String[] args) throws NoSuchMethodException { Method test1 = Main.class.getMethod("test1", Map.class, List.class); //Gets the parameter type of the method Type[] genericParameterTypes = test1.getGenericParameterTypes(); for (Type genericParameterType: genericParameterTypes){ System.out.println(genericParameterType); //Get the structured parameter type of the parameter type, that is, the type in < > if (genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments){ System.out.println(actualTypeArgument); } } } System.out.println("======================================================="); Method test2 = Main.class.getMethod("test2", null); //Get return value type Type genericReturnType = test2.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments){ System.out.println(actualTypeArgument); } } } public void test1(Map<String,User> map, List<User> list){ System.out.println("test1"); } public Map<String,User> test2(){ System.out.println("test2"); return null; } }
2.8 obtaining annotation information by reflection
First, let's know what ORM is, that is, object relationship mapping, that is, object relationship mapping table. As shown below:
- Class corresponds to table structure;
- Attributes correspond to table fields;
- Object corresponds to a row of records in the table.
So how can we complete the mapping relationship between a class and table structure through reflection mechanism and annotation collocation?
public class Main { public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException { Class clazz = User.class; //Get class annotations through reflection Annotation[] annotations = clazz.getAnnotations(); //Gets the specified annotation Table table = (Table)clazz.getAnnotation(Table.class); System.out.println(table); //Gets the value of the specified annotation System.out.println("Table Annotated value Parameter value:"+table.value()); //Get annotation of class attribute Field id = clazz.getDeclaredField("id"); TableField tableField = id.getAnnotation(TableField.class); System.out.println(tableField); System.out.println("TableField Annotated name Parameter value:"+tableField.name()); System.out.println("TableField Annotated type Parameter value:"+tableField.type()); System.out.println("TableField Annotated length Parameter value:"+tableField.length()); } } @Table("user") class User { @TableField(name = "id", type = "Long",length = 10) public Long id; @TableField(name = "name", type = "String",length = 8) public String name; } /** * Annotation of class name * @author Korbin */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Table{ String value(); } /** * Attribute annotation * @author Korbin */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface TableField{ String name(); String type(); int length() default 1; }