Annotation and reflection
What is annotation
-
Annotation is a new technology introduced from JDK5.0.
-
The function of Annotation: > not the program itself, it can explain the program, (this is no different from comments) > it can be read by other programs (such as compilers).
-
Format of Annotation: > Annotation exists in the code as "@ Annotation name". You can also add some parameter values, such as @ SuppressWarnings(value="unchecked")
-
Where can Annotation be used? > can be attached to package, class, method, field, etc., which is equivalent to adding additional auxiliary letters to them. We can access these metadata through reflection mechanism programming
//What is annotation public class Test01 extends Object{ //@Override overridden annotation @Override public String toString() { return super.toString(); } }
Built in annotation
-
@Override: defined in java.lang.override. This annotation is only applicable to rhetoric, indicating that one method declaration intends to override another method declaration in the superclass
-
@Deprecated: defined in java.lang.Deprecated. This annotation can be used for rhetoric, attributes, and classes to indicate that programmers are not encouraged to use such elements, usually because it is dangerous or there are better choices.
-
@suppress Warnings: defined in java.lang.SuppressWarnings to suppress Warnings at compile time
-
Different from the previous two comments, you need to add a parameter to use it correctly. These parameters have been defined. We can use them selectively
-
@SuppressWarnings("all")
-
@SuppressWarnings ("unchecked")
-
@SuppressWarnings(value=("unchecked", "deprecation"})
-
wait
-
//What is annotation @SuppressWarnings("all") //Suppression warning public class Test01 extends Object{ //@Override overridden annotation @Override public String toString() { return super.toString(); } //Deprecated is not recommended for programmers, but it can be used. Or there is a better way @Deprecated public static void test(){ System.out.println("Deprecated"); } public static void main(String[] args) { test(); } }
Meta annotation
-
The function of meta annotation is to annotate other annotations. Java defines four standard meta annotation types, which are used to describe other annotation types
-
These types and the classes they support can be found in the java.lang.annotation package. (@ Target, @Retention, @ documented, @ inherited)
-
@Target: used to describe the scope of use of annotations (i.e. where the described annotations can be used)
-
@Retention: indicates the level at which the annotation information needs to be saved. It is used to describe the annotation life cycle
-
(SOURCE < CLASS < RUNTIME)
-
-
@Document: note that the annotation will be included in the javadoc
-
@Lninherited: indicates that the subclass can inherit the annotation in the parent class
-
//Test meta annotation @MyAnnotation public class Test02 { public void test(){ } } //Define an annotation //Target indicates where our annotation can be used. @Target(value = {ElementType.METHOD,ElementType.TYPE}) //Retention indicates where our annotations are still effective // runtime > class > sources @Retention(value = RetentionPolicy.RUNTIME) //Documented indicates whether to produce our annotations in JAVAdoc @Documented //The Inherited subclass can inherit the annotation of the parent class @Inherited @interface MyAnnotation{ }
Custom annotation
-
When using @ interface to customize annotations, it automatically inherits the java.lang.annotation.Annotation interface
-
analysis
-
@Interface is used to declare an annotation. Format: public @ interface annotation name {definition content}
-
Each of these methods 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)
-
You can declare the default value of the parameter through default
-
If there is only one parameter member, the general parameter name is value
-
An annotation element must have a value. When defining an annotation element, we often use an empty string with 0 as the default value
-
//Custom annotation public class Test03 { //Annotations can display assignments. If there is no default value, we must assign a value to the annotation @MyAnnotation02(name = "maoerxian" ,schools = "university") public void test(){} @MyAnnotation03("maoerxian")//If it is value and the annotation has only one value, value can be omitted public void test2(){} } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation02{ //Annotated parameters: parameter type + parameter name (); String name() default ""; int age() default 0; int id() default -1; //If the module default value is - 1, it means that it does not exist String[] schools(); } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation03{ String value(); }
Reflection mechanism
Static VS dynamic language
Dynamic language
-
It is a kind of language that can change its structure at run time: for example, new functions, objects and even code can be introduced, existing functions can be deleted or other structural changes. Generally speaking, the code can change its structure according to some conditions at run time.
-
Main dynamic languages: Object-C, c#, JavaScript, PHP, Python, etc.
Static language
-
Corresponding to dynamic languages, languages with immutable runtime structure are static languages, such as Java, C and C + +.
-
Java is not a dynamic language, but Java can be called a "quasi dynamic language". That is, Java has certain dynamics. We can use the reflection mechanism to obtain characteristics similar to dynamic language. Java's dynamics makes programming more flexible!
Java Reflection
-
Reflection is the key to Java being regarded as a dynamic language. The reflection mechanism allows programs to obtain the internal information of any class with the help of the reflection API during execution, and can directly operate the internal properties and methods of any object.
-
Class c = Class.forName ("java.lang.String")
-
-
After loading the Class, an object of Class type (a Class has only one Class object) is generated in the method area of the heap memory. This object contains the complete Class structure information. We can see the Class structure through this object. This object is like a mirror. We can see the Class structure through this mirror. Therefore, we vividly call it reflection
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
-
Get generic information at run time
-
Call the member variables and methods of any object at run time
-
Processing annotations at run time
-
Generate dynamic proxy
Advantages and disadvantages of Java reflection
Advantages: it can dynamically create objects and compile, reflecting great flexibility
Disadvantages: it has an impact on performance. Using reflection is basically an interpretive operation. We can tell the JVM what we want to do and it meets our requirements. Such operations are always slower than directly performing the same operation.
Main API s related to reflection
-
Java.lang.Class: represents a class
-
Java.lang.reflect.Method: a method representing a class
-
Java.lang.reflect.Field: represents the member variable of the class
-
Java.lang.reflect.Constructor: constructor representing a class
Class class
The following methods are defined in the Object class, which will be inherited by all subclasses
public final Class getClass()
-
The type of the return value of the above method is a Class class, which is the source of Java reflection. In fact, the so-called reflection will be well understood from the running results of the program, that is, the name of the Class can be obtained through object reflection.
-
The information that can be obtained after the object looks in the mirror: the attributes, methods and constructors of a Class, and which interfaces a Class implements. For each Class, JRE reserves an object of constant Class type. A Class object contains information about a specific structure (class/interface/enum/annotation/primitive type/void / []).
-
Class itself is also 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
-
Each Class instance will remember which Class instance it was generated from
-
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
-
Common methods of Class
Get an instance of Class
a) If a specific class is known, it is obtained through the class attribute of the class. This method is the most safe and reliable, and the program performance is the highest.
Class clazz = Person.class;
b) If the instance of a Class is known, call the getClass0 method of the instance to obtain the Class object
Class clazz = person.getClass0;
C) If the full Class name of a Class is known and the Class is in the Class path, it can be obtained through the static method 1orName0 of Class class, and ClassNotFoundException may be thrown
Class clazz = Class.forName("demo01.Student");
d) The built-in basic data type can directly use the class name. Type
e) You can also use ClassLoader
//What are the creation methods of test Class public class Test03 { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println("This person is:" + person.name); //Method 1: obtained by object Class c1 = person.getClass(); System.out.println(c1.hashCode()); //Method 2: forname Class c2 = Class.forName("com.maoerxian.reflection.Student"); System.out.println(c2.hashCode()); //Method 3: obtained by class name. Class Class c3 = Student.class; System.out.println(c3.hashCode()); //Method 4: wrapper classes of basic built-in types have a Type attribute Class c4 = Integer.TYPE; System.out.println(c4); //Get parent type Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person{ public String name; public Person() { } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person{ public Student(){ this.name = "student"; } } class Teacher extends Person{ public Teacher(){ this.name = "teacher"; } }
What types can have Class objects
-
Class: external class, member (member internal class, static internal class), local internal class, anonymous internal class
-
interface: interface
-
[]: array
-
enum: American drama
-
Annotation: annotation @ interface
-
primitive type: basic data type
-
void
//What are the creation methods of test Class public class Test03 { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println("This person is:" + person.name); //Method 1: obtained by object Class c1 = person.getClass(); System.out.println(c1.hashCode()); //Method 2: forname Class c2 = Class.forName("com.maoerxian.reflection.Student"); System.out.println(c2.hashCode()); //Method 3: obtained by class name. Class Class c3 = Student.class; System.out.println(c3.hashCode()); //Method 4: wrapper classes of basic built-in types have a Type attribute Class c4 = Integer.TYPE; System.out.println(c4); //Get parent type Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person{ public String name; public Person() { } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person{ public Student(){ this.name = "student"; } } class Teacher extends Person{ public Teacher(){ this.name = "teacher"; } }
Java Memory Analysis
Understand the 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 and ClassLoader understanding
-
Load: load the contents of the class file word code 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
-
Link: the process of merging the binary code of Java classes into the running state of eight VM S.
-
Verification: ensure that the loaded class information complies with the JVM specification and there are no security problems
-
Preparation: the stage of formally allocating memory for class variables (static) and setting the default initial value of class variables. These memory will be allocated in the method area.
-
Resolution: the process of replacing the symbolic reference (constant name) in the virtual machine constant pool with a direct reference (address)
-
-
initialization:
-
The process of executing the class constructor < clinit > () method. The class constructor < clinit > () method is generated by the combination of the assignment action of all class variables in the class automatically collected at compile time and the statements in the static code block. (the class constructor constructs class information, not the constructor of the class object)
-
When initializing a class, if it is found that its parent class has not been initialized, the initialization of its parent class needs to be triggered first.
-
Virtual opportunity ensures that the < clinit > () methods of a class are locked and synchronized correctly in a multithreaded environment.
-
public class Test05 { public static void main(String[] args) { A a = new A(); System.out.println(A.m); /* * 1.When loaded into memory, a Class object corresponding to the Class will be generated * 2.Link, m = 0 after link * 3.initialization * <clinit>(){ * System.out.println("A Class static code block initialization ""); m = 300; m = 100 * } * */ } } class A{ static { System.out.println("A Class static code block initialization"); m = 300; } /* m = 300 m = 100 * */ static int m = 100; public A(){ System.out.println("A Class"); } }
When does class initialization occur
-
Active reference of class (class initialization must occur)
-
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 its parent class is not initialized, its parent class will be initialized first
-
-
Passive reference of class (class initialization will not occur)
-
When accessing a static domain, only the class that actually declares the domain 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
-
Reference constants do not trigger the initialization of this class (constants are stored in the constant pool of the calling class in the link phase)
-
//When will the test class initialize public class Test06 { static { System.out.println("Main Class is loaded"); } public static void main(String[] args) throws ClassNotFoundException { //1. Active reference // Son son = new Son(); //Reflection also produces active references // Class.forName("com.maoerxian.reflection.Son"); //A method that does not generate a reference to a class // System.out.println(Son.b); // Son [] array = new son [5]; / / main class is loaded 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 { System.out.println("Subclass loaded"); m = 300; } static int m = 100; static final int M = 1; }
Role of class loader
-
The function of class loading: load the bytecode content of 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 to the class data in the method area.
-
Class caching: the standard JavaSE class loader can find classes as required, but once a class is loaded into the class loader, it will remain loaded (cached) for a period of time. However, the JVM garbage collection mechanism can recycle these class objects
-
Class loader is used to load classes into memory. The JVM specification defines class loaders of the following types.
public class Test07 { public static void main(String[] args) throws ClassNotFoundException { //Gets the loader of the system class ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader);//jdk.internal.loader.ClassLoaders$AppClassLoader@66d3c617 //Gets the parent class loader -- > extension class loader of the system class loader ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent);//jdk.internal.loader.ClassLoaders$PlatformClassLoader@119d7047 //Get the parent class loader -- > root loader (c/c + +) of the extended class loader (if it cannot be read, it will be put back to null) ClassLoader parent1 = parent.getParent(); System.out.println(parent1);//null\ //Test which loader loads the current class ClassLoader classLoader = Class.forName("com.maoerxian.reflection.Test07").getClassLoader(); System.out.println(classLoader);//jdk.internal.loader.ClassLoaders$AppClassLoader@66d3c617 //Test which loader loads the JDK built-in classes classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader);//null //How to get the path that the system class loader can load System.out.println(System.getProperty("java.class.path")); } }
Gets the complete structure of the runtime class
Obtain the complete structure of the runtime class by radiation
Field,Method,Constructor,Superclass,Interface,Annotation
-
All interfaces implemented
-
Inherited parent class
-
All constructors
-
All methods
-
All fields
-
annotation
//Get class information public class Test08 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.maoerxian.reflection.User"); User user = new User(); c1= user.getClass(); //Get the name of the class System.out.println(c1.getName()); //Get package name + class name / / com.maoerxian.reflection.User System.out.println(c1.getSimpleName()); //Or class name / / User //Get the properties of the class System.out.println("================"); Field[] fields = c1.getFields(); //Only public properties can be found fields = c1.getDeclaredFields(); //Find all properties for (Field field : fields) { System.out.println(field); } System.out.println("==========="); //Gets the value of the specified property Field name = c1.getDeclaredField("name"); System.out.println(name); //private java.lang.String com.maoerxian.reflection.User.name //Method to get class System.out.println("==========="); Method[] methods = c1.getMethods();//Get all public methods of this class and its parent class for (Method method : methods) { System.out.println("natural:" + method); } methods = c1.getDeclaredMethods(); //Get all methods of this class for (Method method : methods) { System.out.println("getDeclaredMethods:" + 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); //Gets the specified constructor System.out.println("========================"); Constructor[] constructors = c1.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } constructors = c1.getDeclaredConstructors(); for (Constructor constructor : constructors) { System.out.println("#" + constructor ); } //Gets the specified constructor Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); System.out.println("appoint:" + declaredConstructor); } }
Summary
-
In the actual operation, the operation code to obtain the class information is not often developed
-
Be familiar with the function and reflection mechanism of java.lang.reflect package.
-
If you get the names of properties, methods, constructors, modifiers, etc.
What can I do with a Class object
-
Create Class object: call the newlnstance0 method of Class object
-
1) Class must have a parameterless constructor,
-
2) The constructor of the class needs sufficient access rights
-
-
reflection? Can't you create an object without a parameterless constructor? As long as the constructor in the class is explicitly called and the parameters are passed in during the operation, the operation can be instantiated
-
The steps are as follows:
-
Get the constructor of the specified parameter type of this Class through getdeclaraedconstructor (classparametertypes) of Class class
-
You want to pass an object array into the formal parameters of the constructor, which contains all the parameters required by the constructor.
-
Instantiate objects through Constructor
-
Call the specified method
Through reflection, the Method in the class is called and completed through the Method class.
① Get a Method object through the getMethod(String name, Class..parameterTypes) Method of Class class, and set the parameter type required for this Method operation.
② Then use Object invoke(Object obj, Objectu args) to call and pass the parameter information of the obj object to be set to the method.
Object invoke(Object obj, Object ... args)
-
object corresponds to the return value of the original method. If the original method has no return value, null is returned
-
If the original method is a static method, the formal parameter Object obj can be null
-
If the original method parameter list is empty, Objectl args is null
-
If the original method is declared as private, you need to explicitly call the setAccessible(true) method of the method object before calling the invoke() method to access the private method.
//Dynamically create objects through reflection public class Test09 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //Get Class object Class c1 = Class.forName("com.maoerxian.reflection.User"); //Construct an object //User user = (User)c1.newInstance();// The essence is to call the parameterless constructor of the class //System.out.println(user); //Creating objects through constructors //Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class); //User user2 = (User) constructor.newInstance("maoerxian",001,18); //System.out.println(user2); //Call normal methods by radiation User user3 = (User) c1.newInstance(); //Obtain a method by radiation Method setName = c1.getDeclaredMethod("setName", String.class); //invoke: activate //(object, "value of method") setName.invoke(user3,"maoerxian"); System.out.println(user3.getName()); //Operation properties by reflection User user4 = (User) c1.newInstance(); Field name = c1.getDeclaredField("name"); //Private properties cannot be operated directly. We need to turn off the security detection of the program and setAccessible(true) of the property or method name.setAccessible(true);// name.set(user4,"maoerxian"); System.out.println(user4.getName()); } }
setAccessible
-
Method, Field and Constructor objects all have setAccessible0 method.
-
setAccessible is a switch that enables and disables access security checks.
-
If the parameter value is true, it indicates that the Java language access check should be cancelled when the reflected object is used.
-
Improve the efficiency of reflection. If reflection must be used in the code, and the code of this sentence needs to be called frequently, please set it to true.
-
So that private members that cannot be accessed can also be accessed
-
-
If the parameter value is false, it indicates that the reflected object should implement Java language access check
//Analyze performance issues public class Test10 { //Normal mode call public static void test01(){ 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 call public static void test02() 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"); } //Reflection mode call off detection public static void test03() 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("Close detection and execute 1 billion times:" + (endTime - startTime) + "ms"); } public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { test01();//1 billion times in ordinary way: 5ms test02();//Reflection mode: 1 billion times: 2581ms test03();//1 billion times of closed detection: 1658ms } }
Reflection operation generics
-
Java uses the generic erasure mechanism to introduce generics. Generics in Java are only used by the compiler javac to ensure data security and avoid forced type conversion. However, once the compilation is completed, all types related to generics are erased
-
In order to manipulate these types through reflection, Java has added parameterizedtype, genericarraytype, TypeVariable and WildcardType to represent types that cannot be classified into Class 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 an array type of parameterized type generator type variable
-
TypeVariable: it is the public parent interface of various types of variables
-
WildcardType: represents a wildcard type expression
//Get generics through reflection public class Test11 { public void test01(Map<String,User> map, List<User> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = Test11.class.getMethod("test01", Map.class, List.class); Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("#" + genericParameterType); if (genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } method = Test11.class.getMethod("test02",null); Type genericReturnType = method.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } }
Reflection operation annotation
-
getAnnotations
-
getAnnotation
Exercise: ORM
//Practice reflection annotation public class Test12 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.maoerxian.reflection.Student2"); //Get annotations through reflection Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //Gets the value of the annotated value TableMaoerxian tableMaoerxian = (TableMaoerxian)c1.getAnnotation(TableMaoerxian.class); String vable = tableMaoerxian.value(); System.out.println(vable); //Gets the annotation specified by the class Field f = c1.getDeclaredField("id"); FieldMaoerxian annotation = f.getAnnotation(FieldMaoerxian.class); System.out.println(annotation.columnNmae()); System.out.println(annotation.type()); System.out.println(annotation.length()); } } @TableMaoerxian("db_student") class Student2{ @FieldMaoerxian(columnNmae = "db_id",type = "int",length = 10 ) private int id; @FieldMaoerxian(columnNmae = "db_age",type = "int",length = 10 ) private int age; @FieldMaoerxian(columnNmae = "db_name",type = "varchar",length = 3 ) private String name; public Student2() { } public Student2(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student2{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } } //Annotation of class name @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface TableMaoerxian{ String value(); } //Attribute annotation @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldMaoerxian{ String columnNmae(); String type(); int length(); }