注解的使用

188 阅读4分钟

1 注解的介绍

注解:

jdk1.5版本的特性, 是一个引用数据类型(类,接口,枚举同一级别)

作用:

1 对代码进行解释说明,可以生成API文档

2 检查代码是否有错误(使用时添加@Override)

3 对代码分析,可起到代替配置文件的作用

JDK注解说明:

@Override 检测方法是否为重写方法

  • jdk1.5版本,支持父类的方法重写
  • jdk1.6版本,支持接口的方法重写

@Deorecated 表示方法已经过时,不推荐使用.(调用方法时会有横线,可以使用. 一般官方废除方法,一定会提供一个新的可使用的方法)

@SupperssWarnings 消除警告(常用@SupperssWarnings("all"))

2 注解的格式

自定义注解格式

      修饰符 @interface 注解名{
          属性
      }

属性的定义格式

  • 数据类型 属性名();-->没有默认值的-->需要后面赋值
  • 数据类型 属性名() default 默认值;-->可以改变的

定义的属性类型

  • 八种基本数据类型(int,float,boolean,byte,double,char,long,short)
  • String类型,Class类型,枚举类型,注解类型
  • 以上所有类型的一维数据.

案列

public @interface Food {
    //食物名
    String name();
    //价格
    double price();
    //配料
    String[] compose();

    //数量
    //Integer count();错误,不能使用包装类
    //int count() default 10;这个是可以的,定义属性的时候可以指定默认值
}

3 注解的使用

@Food(name="番茄炒蛋",price=12.00,compose={"番茄","鸡蛋"})
pubilc class TomatoAndEgg{
    
}

说明:

  • 空注解可以直接使用,不需要赋初值
  • 同一个对象中不能连续使用同一个注解多次,但是可以使用多个不同的注解.(注解解析的时候通过反射去解析,多个相同注解,也只会有一个有用)
  • 如果注解中有属性,属性一定要赋初值,有多个属性,使用逗号,隔开.(一般的注释中会给一个默认值)
  • 注解中属性如果有默认值(初值),可以不赋值,反之必须赋初值.
  • 注解中只有一个属性,且属性名为value,我们使用注解时,可以不用写属性名

4 案列1

@Food(name="番茄炒蛋",price=12.00,compose={"番茄","鸡蛋"})
public class TomatoAndEgg {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.反射带有注解得类
        Class c = Class.forName("com.cf.TomatoAndEgg");
        //2.判断这个类上是否有注解
        boolean b = c.isAnnotationPresent(Food.class);
        System.out.println(b);
        if (b){
            Food food = (Food) c.getAnnotation(Food.class);
            //获取注解中的属性值
            System.out.println("菜名:"+food.name());
            System.out.println("价格:"+food.price());
            System.out.println("配料:"+ Arrays.toString(food.compose()));
        }
    }
}

/**
	Q:结果答应为false,TomatoAndEgg类上有注解,为什么程序判断没有?
	A:因为缺少了元注解的管理,注解默认是存在源码中,不在内存中,无法通过反射获取注解属性.
*/

5 元注解

元注解: JDK自带的注解, 管理其他的注解.(自定义的注解)

元注解功能:

  • 控制自定义的注解,可以放置的位置(类/方法/变量/包...)
  • 控制注解的生命周期

元注解属性:

  • @Target 说明其他注解,出现的位置.

    • ElementType[] value(); 数组,可以赋值多个(ElementType是数据类型,是枚举的属性,都是静态修饰,直接类名调用)
      • TYPE 可以写在类上
      • FIELD 可以写在成员变量
      • METHOD 可以写在方法上
      • PARAMETER 可以写在方法参数上
      • CONSTRUCTOR 可以写在构造方法上
  • @Retention 说明其他注解的生命周期

    • RetentionPolicy value(); 不是数组,只能赋值一个(枚举类型,属性都是静态修饰,直接类名调用)
      • SOURCE 默认级别, 注解仅存在于源码中(java文件中,class文件中没有,方法区没有)
      • CLASS 注解存在于编译后的class文件中,方法区没有
      • RUNTIME 注解存在运行时期的内存中,方法区中存在.(只有方法区中出现,才可以利用反射获取)

==ps : @Override 只是检测方法是否为重写方法==

6 案列1plus

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Food {

    //食物名
    String name();
    //价格
    double price();
    //配料
    String[] compose();
}


@Food(name="番茄炒蛋",price=12.00,compose={"番茄","鸡蛋"})
public class TomatoAndEgg {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.反射带有注解得类
        Class c = Class.forName("com.cf.TomatoAndEgg");
        //2.判断这个类上是否有注解
        boolean b = c.isAnnotationPresent(Food.class);
        System.out.println(b);
        if (b){
            Food food = (Food) c.getAnnotation(Food.class);
            //获取注解中的属性值
            System.out.println("菜名:"+food.name());
            System.out.println("价格:"+food.price());
            System.out.println("配料:"+ Arrays.toString(food.compose()));
        }
    }
}

/**
	运行结果如下:
		true
         菜名:番茄炒蛋
         价格:12.0
         配料:[番茄, 鸡蛋]

*/