目录
1、注解
JDK5.0新增 --- 注解(Annotation),也叫元数据。与类、接口、枚举是在同一个层次,它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
2、注解的重要性
Annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的"name=value"对中。在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/ArIdroid中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。未来的开发模式都是基于注解的,JPA(java的持久化API)是基于注解的,Spring2.5以后都是基于注解的,Hibernate3.x以后也是基于注解的,注解是一种趋势,一定程度上可以说 :框架=注解+反射+设计模式。
3、注解的作用分类
编写文档: 通过代码里标识的元数据生成文档【生成文档doc文档】
代码分析: 通过代码里标识的元数据对代码进行分析【使用反射】
编译检查: 通过代码里标识的元数据让编译器能够实现基本的编译检查【Override等】
4、注解分类
注解可以根据注解参数分为三大类:
标记注解: 没有参数的注解,仅用自身的存在与否为程序提供信息,如@Override注解,该注解没有参数,用于表示当前方法为重写方法。
单值注解: 只有一个参数的注解,如果该参数的名字为value,那么可以省略参数名,如 @SuppressWarnings(value = “all”),可以简写为@SuppressWarnings(“all”)。
完整注解: 有多个参数的注解。
1、标记注解
该注解中方法体并没有任何参数,也就是只起到标记作用
@Override注解是一个标记注解
@Target({TYPE,CONSTRUCTOR,METHOD})
public @interface MyAnnotation4 {
}
2、单值注解
在上面我们用到的@SuppressWarnings注解就是一个单值注解。那我们进入到它的源码看一下是怎么个情况。其实,和标记注解比较,它就多一个value参数而已,而这就是单值注解的必要条件,即只有一个参数。并且这一个参数为value时,我们可以省略value。
3、完整注解
上述两个类型注解讲解完,至于完整注解嘛,这下就能更明白了。其中的方法体就是有多个参数而已。
5、JDK内置注解
@Override: 标记在成员方法上,用于标识当前方法是重写父类(父接口)方法,编译器在对该方法进行编译时会检查是否符合重写规则,如果不符合,编译报错。
@Deprecated: 用于标记当前类、成员变量、成员方法或者构造方法过时如果开发者调用了被标记为过时的方法,编译器在编译期进行警告。
@SuppressWarnings: 压制警告注解,可放置在类和方法上,该注解的作用是阻止编译器发出某些警告信息。
@Repeatable:用于注解上,标记该注解可以在同一类中重复使用
1、@Override注解
@Override:限定重写父类方法,该注解只能用于方法
public class Person {
public void eat(){
System.out.println("父类eat..");
}
}
public class Student extends Person {
/*
@Override的作用:限定重写的方法,只要重写方法有问题,就有错误提示。
*/
@Override
public void eat(){
System.out.println("子类eat..");
}
}
在子类中去实现父类的方法,就会在方法上有@Override注解,假如我们试图去重写eat方法名称,会发现在编译期就报错了,就说明该方法不是我们重写其父类(eat)的方法
2、@Deprecated
用于表示所修饰的元素(类,方法,构造器,属性等)已过时。通常是因为所修饰的结构危险或存在更好的选择
我们解释@Deprecated注解就需要模拟一种场景了。假设我们公司的产品,目前是1.0版本。这时候我们为产品的功能又进行了扩展,打算发布V2.0版本。但是,我们V1.0版本的产品需要抛弃吗?也就是说我们V1.0的产品功能还继续让用户使用吗?答案肯定是不能抛弃的,因为有一部分用户是一直用V1.0版本的。如果抛弃了该版本会损失很多的用户量,所以我们不能抛弃该版本。这时候,我们对功能进行了扩展后,发布了V2.0版本,我们给予用户的通知就可以了,也就是告知用户我们在V2.0版本中为功能进行了扩展。可以让用户自行选择版本。
在方法前加入@Deprecated,这个方法就会变成一个废弃方法/过期方法/过时方法
*/
@Deprecated
public void study(){
System.out.println("学习。。");
}
还有例如我们知道Date类中的这些方法已经是过时的了,如果我们使用该方法并执行该程序的话。执行的过程中就会提示该方法已过时的内容,但是只是提示,并不影响你使用该方法。
而这些过时的方法都有@Deprecated注解
3、@SuppressWarnings:
抑制编译器警告 这个抑制警告在idea中不明显,在eclipse才明显
unchecked:未检查的转化,如集合没有指定类型还添加元素
unused:未使用的变量
resource:有泛型未指定类型
path:在类路径,原文件路径中有不存在的路径
deprecation:使用了某些不赞成使用的类和方法
fallthrough:switch语句执行到底没有break关键字
rawtypes:没有写泛型,比如: List list = new ArrayList();
all:全部类型的警告
@SuppressWarnings在IDEA中不明显,在eclipse中有显示黄色警告。
6、元注解
元注解是用于修饰其它注解的注解。
@Target:指定被修饰的注解的作用范围
@Retention:指定了被修饰的注解的生命周期
@Documented:指定了被修饰的注解是可以Javadoc等工具文档化
@Inherited:指定了被修饰的注解修饰程序元素的时候是可以被子类继承的
1、@Target
用于修饰注解的注解,用于指定被修饰的注解能用于修饰哪些程序元素。@Target也包含一个名为value的成员变量。
- ANNOTATION_TYPE 用于描述注解
- CONSTRUCTOR 用于描述构造方法
- FIELD 用于描述属性
- LOCAL_VARIABLE 用于描述局部变量
- METHOD 用于描述方法
- PACKAGE 用于描述包
- PARAMETER 用于描述方法内的参数
- TYPE 用于描述类型进行注解,比如类、接口、枚举
@Target({TYPE,CONSTRUCTOR,METHOD})
public @interface MyAnnotation4 {
}
2、@Retention
@Retention 用于修饰注解,用于指定修饰的那个注解的生命周期,@Rentention包含一个RetentionPolicy枚举类型的成员变量,使用@Rentention时必须为该value成员变量指定值
属性 | 描述 |
RetentionPolicy.SOURCE | 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃; |
RetentionPolicy.CLASS | 注解只被保留到编译进行时的class文件,但 JVM 加载class文件时候被遗弃,也就是在这个阶段不会读取到该class文件。 |
RetentionPolicy.RUNTIME | 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。 |
注意: 我们常用的定义即是RetentionPolicy.RUNTIME
,因为我们使用反射来实现的时候是需要从JVM中获取class类对象并操作类对象的。
三个生命周期是源码阶段
- > class类对象阶段
- > Runtime运行时阶段
。
3、@Documented
用于指定被该元注解修饰的注解类将被javadoc工具提取成文档。默认情况下,javadoc是 不包括注解的,但是加上了这个注解生成的文档中就会带着注解了
如果:Documented注解修饰了Deprecated注解,
那么Deprecated注解就会在javadoc提取的时候,提取到API中:
4、@Inherited
被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
7、自定义注解
格式: public @Interface 注解名 {属性列表/无属性}
而注解体中的属性也是有要求的。其属性要求如下:
注解的属性也叫做成员变量。注解只有成员变量,没有方法。
属性的返回值类型必须是以下几种:
1、基本数据类型
2、String类型
3、枚举类型
4、注解
5、以上类型的数组
注意:1、在这里不能有void的无返回值类型和以上类型以外的类型
2、定义的属性,在使用时需要给注解中的属性赋值
3、如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不为属性赋值,它取的是默认值。如果为它再次传入值,那么就发生了对原值的覆盖。
4、如果只有一个属性需要赋值,并且属性的名称为value,则赋值时value可以省略,可以直接定义值
5、数组赋值时,值使用{}存储值。如果数组中只有一个值,则可以省略{}
package com.mylifes1110.anno;
import com.mylifes1110.enums.Lamp;
public @interface MyAnno {
//基本数据类型
int num();
//String类型
String value();
//枚举类型
Lamp lamp();
//注解类型
MyAnno2 myAnno2();
//以上类型的数组
String[] values();
Lamp[] lamps();
MyAnno2[] myAnno2s();
int[] nums();
}
8、注解应用场景
在javaWeb中,Selvert开发有两种方式,一种是web配置,另一种是注解式开发
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置Servlet-->
<!--配置Servlet的信息-->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.annotation.servlet.HelloServlet</servlet-class>
</servlet>
<!--配置Servlet的映射路径-->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<!--http://localhost:8080/01-hello-servlet/hello-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
注解替代配置文件
package com.bjsxt.servlet;
import javax.servlet.*;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 用于提供服务, 接收请求, 处理响应
*
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
在spring框架就是一个典型的注解式开发
spring注解:
@Param 将参数封装为Map集合
@ResponseBody 将返回的数据转化为JSON串, 如果是字符串本身 原数据返回
@RequestMapping("/hello") 实现浏览器的请求路径与方法的映射
@ComponentScan 包扫描注解 扫描注解
@Bean 标识该方法的返回值交给Spring容器管理
@Scope 控制单例和多例
@Lazy 懒加载
@PostConstruct 初始化方法
@PreDestroy 销毁方法
@Component 将当前类未来的对象交给容器管理
@Autowired 按照类型进行注入
@Qualifier 按照名称进行注入
@Repository 标识持久层注解
@Service 标识Service层
@Controller 标识Controller层
@Value 为属性赋值
@PropertySource 加载指定路径下的配置文件
@Aspect 标识当前类是一个切面类
@Pointcut 用于定义切入点表达式 表达式写法4种
@EnableAspectJAutoProxy 让AOP的注解有效果
@Before AOP-前置通知
@AfterReturning AOP-后置通知
@AfterThrowing AOP-异常通知
@After AOP-最终通知
@Around AOP-环绕通知
@Order(1) //可以利用order关键字 实现AOP的排序 数字越小越先执行
@PathVariable restFul结构,接收参数的注解
@GetMapping("") 只能接收GET请求类型
@DeleteMapping("") 只能接收DELETE请求类型
@PostMapping("") 只能接收POST请求类型
@PutMapping("") 只能接收PUT请求类型
@RestController 表示Controller类,同时要求返回值为JSON
@CrossOrigin 允许跨域访问
@RequestMapping 将公共的部分抽取
@Data lombok动态生成get/set/toString/equals/hashcode等方法
@Accessors(chain = true) 开启链式加载
@NoArgsConstructor 生成无参构造方法
@AllArgsConstructor 生成全参构造方法
@Mapper mybatis将当前的接口交给Spring容器管理. Map<类名小写,JDK动态代理对象>
@SpringBootTest 该注解的作用在进行代码测试时启动spring容器,之后动态的获取对象 注意包路径 主启动类的同包及子包中
@Alisa 设置别名
@MapperScan Mybatis中扫描指定包路径的接口 为其创建代理对象.
@Insert Mybatis 新增操作注解
@Update Mybatis 修改操作注解
@Delete Mybatis 删除操作注解
@Select Mybatis 查询操作注解
@Transactional Spring中用来控制事务
@RestControllerAdvice Controller层的全局异常处理
@ExceptionHandler 按照某种异常类型进行拦@Configuration 标识当前类是配置类
9、注解的提取
注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
然后通过 getAnnotation() 方法来获取 Annotation 对象。
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
或者是 getAnnotations() 方法。
public Annotation[] getAnnotations() {}
前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。
如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了。比如
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
public int id() default -1;
public String msg() default "Hi";
}
TestAnnotation 中 id 属性默认值为 -1,msg 属性默认值为 Hi
因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了,这一步可以省略
@TestAnnotation()
public class Test {}
@TestAnnotation()
public class Test {
public static void main(String[] args) {
boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
if ( hasAnnotation ) {
TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
System.out.println("id:"+testAnnotation.id());
System.out.println("msg:"+testAnnotation.msg());
}
}
}
至此,注解介绍完毕,由于作者水平有限难免有疏漏,欢迎留言纠错。