foreword
What I want to talk about today is annotations. For this chapter, it is best for people with Servlet foundation to read it ~ because if it is purely Java foundation, annotations may not be used. But if you have developed servlets, you @WebServlet
will not be unfamiliar with them.
The current development advocates the use of annotations for development, so that you can avoid writing XML configuration, a very convenient technology~
Learning annotations can better understand how annotations work, and when you see annotations, you can think of how it works~.
If there is any mistake, please bear with me and welcome to correct it in the comment area~
1. What are annotations?
Annotation: Annotation....
Annotations are actually special tags in the code that can be read during compilation, class loading, and runtime, and perform corresponding processing .
2. Why do we need to use annotations?
Traditionally, we tell classes how to behave through configuration files (xml files) .
With annotation technology, we can tell classes how to run through annotations
For example: when we used to write servlets, we needed to configure specific information in the web.xml file
After we use annotations, we can add annotations directly to the Servlet source code... Servlet is configured on Tomcat. In other words, annotations can inject information into classes and methods.
Obviously, this is very intuitive, and the Servlet specification favors this configuration .
3. Basic Annotation
There are 5 basic annotations under the java.lang package, 3 of which are very common.
3.1@Overried
rewrite annotation
If we use the IDE to override the parent's method, we can see it. So what is it good for? ?
@Overried is telling the compiler to check that the method is the implementation of the parent class ... It can help us avoid some low-level errors...
For example, when we implement the equals() method, we mistype euqals(), then the compiler will find that the method does not implement the parent class, which conflicts with the annotation @Overried, so it will give an error .
3.2@Deprecated
Obsolete annotation
This annotation is also very common. When Java is designed, it may feel that some methods are not well designed. In order to be compatible with previous programs, it cannot be directly discarded, so it is set as obsolete .
toLocalString() in the Date object is set to obsolete
@Deprecated
public String toLocaleString() {
DateFormat formatter = DateFormat.getDateTimeInstance();
return formatter.format(this);
}
When we call it in the program, a horizontal bar will appear on the IDE, indicating that the method is obsolete.
3.3@SuppressWarnings
Suppress compiler warning annotations
This annotation is not very common when we write programs, we can use it to make the compiler not give us a warning
When we are using a collection, if no generic type is specified, a warning of security check will be prompted
If we add the @SuppressWarnings annotation to the class, the compiler will not give us a warning
3.4@SafeVarargs
Java 7 "heap pollution" warning
What is heap pollution? ? When assigning a non-generic collection to a generic collection , this situation is prone to heap pollution....
This annotation is also used to suppress compiler warnings... It is not used much, and I will not explain it in detail... Come back and fill in the pit when it is useful.
3.5@FunctionalInterface
@FunctionalInterface is used to specify that the interface is a functional interface
Use this annotation to explicitly specify that the interface is a functional interface.
Fourth, the basis of custom annotations
The above explains the five annotations under the java.lang package. We can write annotations ourselves and inject information into methods or classes .
##4.1 Marking Annotation ##
An annotation without any member variables is called a marker annotation, and @Overried is a marker annotation
//有点像定义一个接口一样,只不过它多了一个@
public @interface MyAnnotation {
}
4.2 Metadata Annotation
Our custom annotations can have member variables, and defining annotations with member variables is called metadata Annotation
Defining member variables in annotations, the syntax is similar to declaring methods. …
public @interface MyAnnotation {
//定义了两个成员变量
String username();
int age();
}
Note: The member variables defined on the annotation can only be String, array, Class, enumeration class, annotation
Some people may be wondering, why should annotation member variables be defined on annotations? ? It sounds complicated....
As mentioned above, the role of annotations is to inject information into classes and methods. Then we often use XML files to tell the program how to run. XML is often nested
<书>
<作者>zhongfucheng</作者>
<价钱>22222</价钱>
</书>
Then, when we use annotations, we may also need to have nesting, so it is allowed to define member variables as annotations on annotations.
4.3 Using custom annotations
We have defined an annotation above, let's use it
4.3.1 General use
Below I have an add method that requires username and age parameters. We use annotations to let the method have these two variables !
//注解拥有什么属性,在修饰的时候就要给出相对应的值
@MyAnnotation(username = "zhongfucheng", age = 20)
public void add(String username, int age) {
}
4.3.2 Default value
Of course, we can give default values when annotating properties . Then, when modifying, you don't need to specify it specifically.
public @interface MyAnnotation {
//定义了两个成员变量
String username() default "zicheng";
int age() default 23;
}
- There is no need to give specific values when modifying
@MyAnnotation()
public void add(String username, int age) {
}
4.3.3 Annotation attribute is value
There is also a special case. If there is only one attribute on the annotation, and the name of the attribute is value , then when using it, we can assign it directly without writing value.
public @interface MyAnnotation2 {
String value();
}
- Using annotations, you can assign values directly without specifying a value
@MyAnnotation2("zhongfucheng")
public void find(String id) {
}
4.4 Inject the basic information of the custom annotation into the method
We have used annotations above, but so far the information on the annotation is not related to the information on the method .
When we use Servlet annotation, we just call the annotation, then the annotation will take effect. This is what the web container implements internally . The custom annotations we write ourselves need to be handled by ourselves .
Now the question is, how do we inject the information on the annotation into the method? ? ? We use reflection technology
The steps can be divided into three parts:
- reflect the methods of this class
- Get the specific information on the annotation through the method
- Inject the information on the annotation into the method
//反射出该类的方法
Class aClass = Demo2.class;
Method method = aClass.getMethod("add", String.class, int.class);
//通过该方法得到注解上的具体信息
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
String username = annotation.username();
int age = annotation.age();
//将注解上的信息注入到方法上
Object o = aClass.newInstance();
method.invoke(o, username, age);
When we execute, we find that there will be an exception...
At this point, we need to add such a code to the custom annotation** (we will talk about why this code is added below)**
@Retention(RetentionPolicy.RUNTIME)
When we execute it again, we will find that we can inject information into the method through annotations.
5. Meta Annotation of JDK
Earlier we have introduced several basic annotations under the java.lang package. In JDK, in addition to Annotation under the java.lang package, there are also several commonly used meta Annotations under java.lang.annotation.
Several meta Annotations under the annotation package are used to modify other Annotation definitions .
5.1@Retention
When injecting the annotation information into the method above, we added the @Retention annotation at the end....Otherwise, an error will be reported .. What is it used for?
@Retention can only be used to modify other Annotations, to specify how long the modified Annotation is retained.
@Retention contains a value variable of type RetentionPolicy , so when using it, you must assign a value to the value member variable
The value variable has only three values:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
A java file has three phases: compile, class, and run. @Retention defaults to class
Earlier we used reflection to get the information on the annotation, because @Retention is class by default, and reflection is to obtain information at runtime . Therefore, the information of Annotation cannot be obtained. So, you have to modify its RetentionPolicy value on the custom annotation
5.2@Target
@Target can only be used to modify another Annotation , it is used to specify which program units the modified Annotation is used to modify
@Target has only one value member variable, and the value of this member variable is as follows:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE
}
If @Target specifies ElementType.ANNOTATION_TYPE, then the modified Annotation can only modify Annotaion
5.3@Documented
@Documented is used to specify that the Annotation class modified by this Annotation will be extracted into a document by the javadoc tool .
The meta Annotation is used very little....
5.4@Inherited
@Inherited is also used to modify other Annotations, and the modified Annotation will have inheritance. . .
example:
- @xxx is my custom annotation, I now use @xxx annotation on the Base class....
- Use @Inherited to decorate @xxx annotations
- When a class inherits the Base class, the implementation class automatically has the @xxx annotation
6. Injecting objects into methods or member variables
6.1 Injecting objects into methods
Earlier we can use annotations to inject basic information into methods, now what we want to use is to inject objects into methods ...
As mentioned above, only member variables such as String, enumeration class, and Double can be defined on annotations. How to inject objects into methods?
6.1.2 Simulation scenario:
- Person class, defines username and age properties, has getter and setter methods for uername and age
public class Person {
private String username;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- PersonDao class, PersonDao class defines Person object and has setter and getter methods of person
public class PersonDao {
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
- Now all I have to do is: use the annotation to inject the Person object into the setPerson() method, thereby setting the person property of the PersonDao class
public class PersonDao {
private Person person;
public Person getPerson() {
return person;
}
//将username为zhongfucheng,age为20的Person对象注入到setPerson方法中
@InjectPerson(username = "zhongfucheng",age = 20)
public void setPerson(Person person) {
this.person = person;
}
}
step:
①: Customize an annotation, the attribute is consistent with the JavaBean class
//注入工具是通过反射来得到注解的信息的,于是保留域必须使用RunTime
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectPerson {
String username();
int age();
}
②: Write an injection tool
//1.使用内省【后边需要得到属性的写方法】,得到想要注入的属性
PropertyDescriptor descriptor = new PropertyDescriptor("person", PersonDao.class);
//2.得到要想注入属性的具体对象
Person person = (Person) descriptor.getPropertyType().newInstance();
//3.得到该属性的写方法【setPerson()】
Method method = descriptor.getWriteMethod();
//4.得到写方法的注解
Annotation annotation = method.getAnnotation(InjectPerson.class);
//5.得到注解上的信息【注解的成员变量就是用方法来定义的】
Method[] methods = annotation.getClass().getMethods();
//6.将注解上的信息填充到person对象上
for (Method m : methods) {
//得到注解上属性的名字【age或name】
String name = m.getName();
//看看Person对象有没有与之对应的方法【setAge(),setName()】
try {
//6.1这里假设:有与之对应的写方法,得到写方法
PropertyDescriptor descriptor1 = new PropertyDescriptor(name, Person.class);
Method method1 = descriptor1.getWriteMethod();//setAge(), setName()
//得到注解中的值
Object o = m.invoke(annotation, null);
//调用Person对象的setter方法,将注解上的值设置进去
method1.invoke(person, o);
} catch (Exception e) {
//6.2 Person对象没有与之对应的方法,会跳到catch来。我们要让它继续遍历注解就好了
continue;
}
}
//当程序遍历完之后,person对象已经填充完数据了
//7.将person对象赋给PersonDao【通过写方法】
PersonDao personDao = new PersonDao();
method.invoke(personDao, person);
System.out.println(personDao.getPerson().getUsername());
System.out.println(personDao.getPerson().getAge());
③: Summarize the steps
In fact, we inject the object into the method like this:
- Get the properties you want to inject into the class
- get the object of this property
- Get the write method corresponding to the attribute
- Get annotations by writing methods
- Get annotation details
- Inject the annotation information into the object
- Call the property write method to inject the object filled with data into the method
6.2 Injecting objects into member variables
The above has said how to inject objects into methods, so injecting into member variables is also very simple.
step:
①: Use annotations on member variables
public class PersonDao {
@InjectPerson(username = "zhongfucheng",age = 20) private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
②: Write an injection tool
//1.得到想要注入的属性
Field field = PersonDao.class.getDeclaredField("person");
//2.得到属性的具体对象
Person person = (Person) field.getType().newInstance();
//3.得到属性上的注解
Annotation annotation = field.getAnnotation(InjectPerson.class);
//4.得到注解的属性【注解上的属性使用方法来表示的】
Method[] methods = annotation.getClass().getMethods();
//5.将注入的属性填充到person对象上
for (Method method : methods) {
//5.1得到注解属性的名字
String name = method.getName();
//查看一下Person对象上有没有与之对应的写方法
try {
//如果有
PropertyDescriptor descriptor = new PropertyDescriptor(name, Person.class);
//得到Person对象上的写方法
Method method1 = descriptor.getWriteMethod();
//得到注解上的值
Object o = method.invoke(annotation, null);
//填充person对象
method1.invoke(person, o);
} catch (IntrospectionException e) {
//如果没有想对应的属性,继续循环
continue;
}
}
//循环完之后,person就已经填充好数据了
//6.把person对象设置到PersonDao中
PersonDao personDao = new PersonDao();
field.setAccessible(true);
field.set(personDao, person);
System.out.println(personDao.getPerson().getUsername());
7. Summary
①: Steps of injecting objects: Get the properties of the object you want to inject, get the annotation information through the properties, inject the annotation information into the object through the property writing method, and finally assign the object to the class .
②: Annotation is actually two functions:
- Let the compiler check the code
- Inject data into methods, member variables, classes
③: Annotations in JDK are divided into
- Basic Annotation
- Under the lang package, it is often used to mark the method, suppress compiler warnings, etc.
- Former Annotaion
- Under the annotation package, it is often used to modify other Annotation definitions
If there are any mistakes in the article, please correct me, and we can communicate with each other. Students who are accustomed to reading technical articles on WeChat and want to get more Java resources can follow WeChat public account: Java3y