JavaSE Annotation 注解
注解,或者叫做注释类型(这里要与Java中的注释符//与/**/区分开),英文单词是Annotation,注解是一种引用数据类型,编译之后也是生成xxx.class文件。
语法格式如下:
[修饰符列表] @interface 注解类型名{
}
注解的使用:
第一:注解使用时的语法格式是:
@注解类型名
第二:注解可以出现在类上、属性上、方法上、变量上等……,注解还可以出现在注解类型上;
1、自定义注解并使用注解
1.1 自定义一个注解
package com.xuanfeng.annotation;
public @interface MyAnnotation {
}
1.2 使用注解
package com.xuanfeng.annotation;
// 默认情况下注解可以出现在任何位置
// 注解出现在类上
@MyAnnotation
public class AnnotationTest01 {
// 出现在实例变量上
@MyAnnotation
private int no;
// 出现构造方法上
@MyAnnotation
public AnnotationTest01(){
}
// 在静态实例方法上,注解修饰形参
@MyAnnotation
public static void m1(@MyAnnotation String name){
}
// 实例方法上
@MyAnnotation
public void m2(){
// 局部变量上
@MyAnnotation
int i = 1;
}
}
// 出现在接口上
@MyAnnotation
interface MyInterface{
}
// 出现在枚举类型上
@MyAnnotation
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}
注解修饰注解:
package com.xuanfeng.annotation;
// 注解修饰注解
@MyAnnotation
public @interface OtherAnnotation {
}
2、JDK内置注解
java.lang包下主要有三个:
Deprecated :用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。
Override :表示一个方法声明打算重写超类中的另一个方法声明。
SuppressWarnings :指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。
这里掌握前两个即可;后面那个作为了解。
2.1 @Override
关于JDK lang包下的Override注解,源代码如下:
public @interface Override {
}
标识性注解,是给编译器做参考,编译器看到一个类的方法上有这个注解的时候,编译器会自动检查该方法是否重写了父类的方法,如果该方法不是重写父类的方法,则编译器报错。
这个注解只是在编译阶段起作用,和运行阶段无关!
package com.xuanfeng.annotation;
public class AnnotationTest02 {
// 下面的方法是重写了父类(Object)中的toString方法
@Override
public String toString() {
return "Annotation";
}
// 这里会报错,因为被@Override修饰的方法不是重写父类的方法
// @Override
// public String tostring() {
// return "Annotation";
// }
}
2.2 元注解
用来标识“注解类型”的注解,称为元注解,常见的元注解有Target、Retention。
关于Target注解:(掌握)
-
这是一个元注解,用来标识“注解类型”的注解;
-
这个Target注解用来标识“被标注的注解”可以出现在那些位置上;
-
@Target(ElementType.METHOD):表示“被标识的注解”只能出现在一个类的方法上;
关于Retention注解:(掌握)
- 这个也是一个元注解;
- 这个注解用来标识“被标识的注解”最终保存在哪里;
@Retention(RetentionPolicy.SOURCE):表示该注解只被保留在Java原文件中;
@Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中;
@Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,并且可以使用反射机制;
如以下代码:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
2.3 @Deprecated
package com.xuanfeng.annotation;
public class AnnotationTest03 {
public static void main(String[] args) {
Test test = new Test();
// 调用一个对象的方法出现了横线,表示该对象的该方法已经过时
test.doSomething();
}
}
class Test{
// 使用@Deprecated修饰一个方法,表示该方法已经过时或者有更好的解决方案存在
@Deprecated
public void doSomething(){
System.out.println("doSomething!");
}
public void doOther(){
System.out.println("doOther!");
}
}
使用过时的方法,编译器会有一下提示:
3、注解的属性
自定义注解中如果存在属性,那么我们在使用该注解的时候必须给没有赋默认值的属性赋值。
自定义MyAnnotation注解:
package com.xuanfeng.annotattion2;
public @interface MyAnnotation {
// 我们通常在注解当中可以定义属性,一下这个是MyAnnotation的name属性;
// 看着像一个方法,但实际上是一个name属性;
String name();
// 指定age属性的默认值为20
int age() default 20;
}
使用MyAnnotation注解:
package com.xuanfeng.annotattion2;
public class MyAnnotationTest {
// 报错,即如果一个注解当中有属性且该属性没有赋初始值,则我们只使用时必须指定
/*@MyAnnotation
public void doSome(){
}*/
// 赋值方式为:@MyAnnotation(属性名=属性值),多个属性之间的赋值是用逗号隔开
// 由于在MyAnnotation注解中已经指定了age属性的值,这里也可以不用赋值
@MyAnnotation(name = "xuanfeng")
public void doSome(){
}
}
注:如果一个注解的属性名是value,并且只有一个属性,则在使用该注解并对注解属性赋值时属性名可以不写。
4、注解属性的类型
枚举类型属性的类型可以为以下的类型已经以下每种类型数组的形式。
byte, short, int , long , flout, double, boolean, char, String, Class, 枚举类型
枚举类型:
package com.xuanfeng.annotation3;
// 枚举类型
public enum Season {
SPRINT,SUMMER,AUTUMN,WINTER
}
注解:
package com.xuanfeng.annotation3;
public @interface OtherAnnotation {
// 年龄属性
int age();
// 邮箱属性
String[] email();
// 季节数组属性
Season[] season();
}
使用注解:
package com.xuanfeng.annotation3;
public class OtherAnnotationTest {
// 如果注解的属性是数组,且赋值的时候只有一个值时,外面的大括号可以省略
@OtherAnnotation(age = 30,email = {"zhangsan@qq.com", "liming@zh.com"}, season = {Season.SPRINT,Season.AUTUMN})
public void doSome(){
}
// 省略数组外面的大括号
@OtherAnnotation(age = 2, email = "zhangsan@qq.com", season = Season.AUTUMN)
public void doOther(){
}
}
5、通过反射获取注解
在文章前面讲到过,元注解@Target可以设置注解在类中出现的位置,@Retention可以设置注解保存的位置;接下来通过这两个元注解来实现更有意义的事情。
自定义注解:
package com.xuanfeng.annotation4;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 自定义注解且该注解只能标注类与方法
@Target({ElementType.TYPE, ElementType.METHOD})
// 希望这个注解可以被反射到
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "贵州师范大学";
}
使用注解:
package com.xuanfeng.annotation4;
@MyAnnotation
public class MyAnnotationTest {
}
通过反射获取注解的值(重要):
package com.xuanfeng.annotation4;
public class ReflectAnnotationTest {
public static void main(String[] args) throws Exception{
// 获取MyAnnotationTest类
Class<?> aClass = Class.forName("com.xuanfeng.annotation4.MyAnnotationTest");
// 判断该类上面有是否存在@MyAnnotation注解
// System.out.println(aClass.isAnnotationPresent(MyAnnotation.class)); // true
if (aClass.isAnnotationPresent(MyAnnotation.class)){
// 获取该注解对象
MyAnnotation myAnnotation = aClass.getAnnotation(MyAnnotation.class);
// 输出注解value属性的值
System.out.println(myAnnotation.value()); // 贵州师范大学
}
}
}
6、注解在开发中的使用
自定义一个注解,判断被该注解标记的类中是否有int类型的id属性,如果没有则报:“被MustHasIdProperty注解标注的类中没有int类型的id属性异常“
注解:
package com.xuanfeng.annotation6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解@MustHasIdProperty主要是用来检查一个类的属性中是否存在int id,如果没有则报异常。
*/
// 表示该注解只能出现在方法上
@Target(ElementType.TYPE)
// 该注解可以被反射机制读取
@Retention(RetentionPolicy.RUNTIME)
public @interface MustHasIdProperty {
}
自定义异常:
package com.xuanfeng.annotation6;
public class HasNotIdPropertyException extends RuntimeException{
public HasNotIdPropertyException() {
}
public HasNotIdPropertyException(String message) {
super(message);
}
}
User类:
package com.xuanfeng.annotation6;
// 用户类,使用MustHasIdProperty进行标注,检测类中是否有int id
@MustHasIdProperty
public class User {
// private int id;
private String username;
private String password;
}
测试:
package com.xuanfeng.annotation6;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws Exception {
// 获取类
Class<?> cUser = Class.forName("com.xuanfeng.annotation6.User");
// 判断类上是否存在@MustHasIdProperty注解
if (cUser.isAnnotationPresent(MustHasIdProperty.class)){
// 当一个类上面有@MustHasIdProperty注解的时候,要求类中必须有int id;否则报异常
// 获取类的属性
Field[] userFields = cUser.getDeclaredFields();
// 标志位
boolean flag = false;
for (Field field: userFields){
// "id".equals(field.getName() 判断是否存在id
// "int".equals(field.getType().getSimpleName()) 判断id类型是否为int
if ("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
flag = true;
}
}
if (!flag){
throw new HasNotIdPropertyException("被MustHasIdProperty注解标注的类中没有int类型的id属性异常");
}
}
}
}
最后:注解在以后的开发中使用的挺多的,这里做一个基本的了解即可,后面还会遇到。