java中你可能不知到的那些事-注解

一、什么是注解

概念: 说明程序的,给计算机看的。
注释: 用文字描述程序,给程序员看的。

Annotation是JDK1.5开始引入的新特性

使用: 可以标注在方法、变量、参数和包等

作用: 可以被其它程序,比如编译器读取

格式: 以@注释名在代码中存在,可以添加参数值
例: @SupperssWarnings(value=“unchecked”)
获取: 通过反射机制变成实现对这些元数据的控制

二、内置注解
  • @Override:定义在 java.lang.Override中,此注释可以用于修饰方法,表示一个方法声明打算重写超类中的另一个方法声明
  • @Deprecated: 定义在java.lang.Deprecated中,可以用于修饰方法,属性,类,表示不鼓励使用这样的元素,通常是它很危险,或者有更好的选择
  • @SupperssWarnings:定义在java.lang.SupperssWarnings中,用来抑制编辑时的警告信息,与前两个注解不同,需要添加额外的参数才能使用
  • @SupperssWarnings(“all”)
  • @SupperssWarnings(“uncheked”)
  • @SupperssWarnings(value={“uncheked”,“deprecation”})
import java.util.Date;

public class Main {
    //@Deprecated修饰该方法时,表示该方法不建议被使用
    @Deprecated
    public static void test() {
        System.out.println("Deprecated Method");
    }
    
    public static void test1() {
        System.out.println("Normal Method");
    }

    public static void testDate() {
        Date date = new Date();
        //Date是时间/日期类,java已不建议使用该类
        System.out.println(date.getYear());
    }

    public static void main(String[] args) {
        test();
        test1();
        testDate();
    }

}
  1. test() 被 @Deprecated 标注,意味着建议不再使用 test(); test() 的定义和调用时,都会一横线。这一横线是编译器对 @Deprecated 方法的处理。test1() 没有被 @Deprecated 标注,它的显示正常。

  2. testDate() 调用了 Date 的相关方法,而 java 已经建议不再使用 Date 操日期/时间。因此,在调用 Date的API 时,会产生警告信息,途中的warnings。

三、自定义注解

注解的定义很像接口的定义,并且与其他任何Java接口一样,注解也将会编译成class文件。

//元注解
public @interface MyAnnotation {

}

编译和反编译:
在这里插入图片描述
本质:

public interface MyAnnotation extends java.lang.annotation.Annotation {
}

通过编译和反编译可以看出,通过@interface定义的注解,它的本质是个接口,所以,我们得出结论,注解本质就是要一个接口,该接口默认继承Annotation 接口。

属性:接口中的抽象方法

  • 属性的返回值类型
  1. 基本数据类型
  2. String类型
  3. 枚举
  4. 注解
  5. 以上类型的注解
public @interface MyAnnotation {
    int age();

    String name() default "张三";

    String[] str();

}

@MyAnnotation(age=15,str={"张三","李四"})
class Test{

}

定义了属性,在需要时给属性赋值

  1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
    2.如果只有一个属性需要赋值,并且属性的名称时value,则value可以省略,直接定义值即可
    3.数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}可以省略
四、元注解

用于描述注解的注解
首先看一下@Override注解

@Target(ElementType.METHOD) //作用的位置,在方法上
@Retention(RetentionPolicy.SOURCE)//保留到什么时候,保留到源码中
public @interface Override {
}

@Target:表示该注解可以用到什么地方。

参数说明
CONSTRUCTOR构造器的声明
FIELD域声明(包括enum实例)
LOCAL_VARIABLE局部变量声明
METHOD方法声明
PACKAGE包声明
PARAMETER参数声明
TYPE类、接口(包括注解类型)或enum声明

@Retention:表示需要在什么级别保存该注解信息。

参数说明
SOURCE注解将被编译器丢弃
CLASS注解在class中可用,但会被JVM丢弃
RUNTIMEJVM将在运行期也保留注解,因此可以通过反射机制读取注解的信息

@Documented:描述注解是否被抽取到api文档中

@Inherited:允许子类继承父类中的注解

Target源码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

Target里只有一个ElementType数组,那ElementType是什么呢?查看源码

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

我们发现ElementType 是个枚举,那怎么用呢

在这里插入图片描述

当我们定义@Target(ElementType.TYPE)表示MyAnnotation注解只能作用于类上,在方法上不能使用该注解
当然,ElementType是个数组,可以定义多个值,就像这样

@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
    @interface MyAnnotation{
    }

其它元注解就不一一细说了

当我们编写好我们的注解后如果没有用来读取注解的工具的话,那么注解对于我们来说也就没有太大意义了。在Java SE5扩展了反射机制的API,以帮助程序员构造这类工具。

先定义一个简单的注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Person{
    String name() default "I don't have name";
	int age() default 21;
}

注解用于一个实体类中:

 class MyAnnotation {

    @Person(name = "My name is zhy")
    public String zhy(){
        return "zhy";
    }

    @Person(name = "My name is xyx", age = 19)
    public String xyx(){
        return "xyx";
    }

}

通过反射机制查找注解中的信息


public class MyAnnotationTest {

    public static void test(List<Integer> ages, Class<?> cl){
        Method[] methods = cl.getDeclaredMethods();
        for(Method method : methods){
            Person person = method.getAnnotation(Person.class);
            if(person != null){
                System.out.println("My name is " + person.name() + " and I'm " + person.age());
                ages.remove(new Integer(person.age()));
            }
        }

        for(int i : ages){
            System.out.print("Missing age is " + i);
        }
    }

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list, 20, 21, 22);
        test(list, MyAnnotation.class);
    }

}

输出:

My name is My name is zhy and I'm 21
My name is My name is xyx and I'm 19
Missing age is 20Missing age is 22

在这个注解处理器程序中,我们用到了两个反射的方法:getDeclaredMethods()和getAnnotation(),这两个都是AnnotatedElement接口(Class、Method和Field等类都实现了该接口)。getAnnotation()方法返回指定类型的注解对象,在这里就是Person。如果被注解的方法上没有该类型的注解,则返回null值。然后我们通过调用name()和age()方法从Person对象中提取元素的值。

总结

以上就是java注解的使用,通过一个简单的案例来说明注解的使用再合适不过了,对于注解的理解在我们平常的使用过程中也能更加得心应手。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值