官方释义:注解是一系列元数据,它提供数据用来解释
程序代码,但是注解并非
是所解释的代码本身
的一部分。注解对于代码的运行效果没有直接影响。注解有许多用处,主要如下:
根据注解是否包含成员变量,可以把注解分为两类:
定义注解使用@interface关键字,可以包含属性。注解的属性也叫做成员变量。注解只有成员变量,没有方法
。注解的成员变量在注解的定义
中以无形参的方法
形式来声明
,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。在使用
的时候,我们应该给注解的属性进行赋值
。如果指定了默认值,使用该注解时可以不为有默认值的成员变量指定值。
在注解中定义属性时它的类型必须是 8 种基本数据类型
外加 类、接口、注解
及它们的数组
。
//代码定义了 TestAnnotation 这个注解中拥有 id 和 msg 两个属性。==============普通应用
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int id() default 0; //指定了默认值为0
String msg();
}
//使用时需赋值,方式是在注解的括号内以 value="" 形式,多个属性之前用 ,隔开
@TestAnnotation(id=3,msg="hello annotation")
public class Test {
}
//注解中属性可以有默认值,默认值需要用 default 关键值指定。==============设置默认值
@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()
public class Test {}
//如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内。==============仅一个属性
public @interface Check {
String value();
}
@Check("hi")
int a;
//这和下面的效果是一样的
@Check(value="hi")
int a;
//最后,还需要注意的一种情况是一个注解没有任何属性。比如==============没有属性
public @interface Perform {}
//那么在应用这个注解的时候,括号都可以省略。
@Perform
public void testMethod(){}
通过用标签来比作注解,前面的内容是讲怎么写注解,然后贴到哪个地方去,而现在我们要做的工作就是检阅这些标签内容。 形象的比喻就是你把这些注解标签在合适的时候撕下来,然后检阅
上面的内容信息。
注解的提取需要借助于 Java 的反射技术
。反射比较慢,所以注解使用时也需要谨慎计较时间成本
。
//举例:检阅注解在类上的注解
@TestAnnotation()
public class Test {
public static void main(String[] args) {
//通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
if ( hasAnnotation ) {
//通过 getAnnotation() 方法来获取 Annotation 对象
TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
//或者是 getAnnotations() 方法。
//public Annotation[] getAnnotations() {}
//前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。
//如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了
System.out.println("id:"+testAnnotation.id());
System.out.println("msg:"+testAnnotation.msg());
}
}
}
//举例:检阅属性、方法上的注解
@TestAnnotation(msg="hello")
public class Test {
@Check(value="hi")
int a;
@Perform
public void testMethod(){}
@SuppressWarnings("deprecation")
public void test1(){
Hero hero = new Hero();
hero.say();
hero.speak();
}
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());
}
try {
Field a = Test.class.getDeclaredField("a");
a.setAccessible(true);
//获取一个成员变量上的注解
Check check = a.getAnnotation(Check.class);
if ( check != null ) {
System.out.println("check value:"+check.value());
}
Method testMethod = Test.class.getDeclaredMethod("testMethod");
if ( testMethod != null ) {
// 获取方法中的注解
Annotation[] ans = testMethod.getAnnotations();
for( int i = 0;i < ans.length;i++) {
System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
}
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
提示子类要复写父类中的方法时,用 @Override 修饰要复写的方法
用来标记过时的元素,想必大家在日常开发中经常碰到。编译器在编译阶段遇到这个注解时会发出提醒警告,告诉开发者正在调用一个过时的元素比如过时的方法、过时的类、过时的成员变量。比如:
定义了一个 Hero 类,它有两个方法 say() 和 speak() ,其中 say() 被 @Deprecated 注解。
public class Hero {
@Deprecated
public void say(){
System.out.println("Noting has to say!");
}
public void speak(){
System.out.println("I have a dream!");
}
}
然后我们在 IDE 中分别调用它们。可以看到,say() 方法上面被一条直线划了一条,这其实就是编译器识别后的提醒效果。
阻止警告
参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。
函数式接口注解
存在于java.lang.annotation包下,共5个。用于修饰其他注解。
Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。
它的取值如下:
源码阶段
保留,在编译器进行编译时它将被丢弃忽视。 编译阶段
,它并不会被加载到 JVM 中。 运行阶段
,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。//应用举例
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}
@Target 指定了注解运用的地方。
原本标签是你想张贴到哪个地方就到哪个地方,但是因为 @Target 的存在,它张贴的地方就非常具体了,比如只能张贴到方法上、类上、方法参数上等等。
@Target 有下面的取值:
注解
进行注解构造方法
进行注解属性
进行注解局部变量
进行注解方法
进行注解包
进行注解方法内的参数
进行注解类
型进行注解,比如类、接口、枚举 @Documented能够将注解中的元素包含到 Javadoc 中去
如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
//应用举例
//注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}
@Test
public class A {}
public class B extends A {}
Java 1.8 才加进来的,表示该注解可重复使用
//@Repeatable 注解了 Person。而 @Repeatable 后面括号中的Persons类相当于一个容器注解。
//什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是数组
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface Person{
String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。
分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式:
(1)在SpringMVC 的配置文件中定义MyController 的bean 对象。
(2)在SpringMVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。
继承自@Controller注解
可用于类或方法上,用来处理请求地址映射的注解。
用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
用方法上,value 表示访问该方法的 URL 地址。
RequestMapping注解有六个属性:
@Configuration 是一个类级注释,指示对象是一个bean定义的源。@Configuration 类通过 @bean 注解的公共方法声明bean。
https://blog.csdn.net/briblue/article/details/73824058 —注解入门
https://blog.csdn.net/javazejian/article/details/71860633 —深入理解Java注解类型
https://www.cnblogs.com/leskang/p/5445698.html —springmvc常用注解标签详解
https://www.cnblogs.com/caoyc/p/5635173.html —@RequestMapping