JavaSE注解

注解(Annotation)

参考文章:https://zhuanlan.zhihu.com/p/37701743

理解注解

注解如同一张标签。标签具备对于抽象事物的解释。

想象代码具有生命,注解就是对于代码中某些鲜活个体的贴上去的一张标签。

注解的定义

理解:一张名字为TestAnnotation的标签。

public @interface TestAnnotation {}

注解的使用

理解:将TestAnnotation标签贴到Test这个类上面

@TestAnnotation
public class Test {}

元注解

元注解是可以注解到注解上的注解(元注解是一种基本注解,但它能够应用到其它注解上面)。

元注解有5种:

@Rentention
@Documented
@Target
@Inherited
@Repeatable

@Retention

Retention 英文释义:保留期

当 @Retention 应用到一个注解上时,它解释说明了这个注解的存活时间。

取值

@Retention(参数)作用
RetentionPolicy.SOURCE注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS注解只被保留到编译进行的时候,不会被加载到 JVM 中。
RetentionPolicy.RUNTIME注解可以保留到程序运行的时候,它会被加载到 JVM 中,所以程序运行时可以获取到它们。

实例

@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {}

@Documented

它能够将注解中的元素包含到 Javadoc 中。

@Target

@Target 指定了注解运用的地方。(限制修饰目标注解运用的场景)

取值

@Target(参数)作用
ElementType.ANNOTATION_TYPE可以给一个注解进行注解
ElementType.CONSTRUCTOR可以给构造方法进行注解
ElementType.FIELD可以给属性进行注解
ElementType.LOCAL_VARIABLE可以给局部变量进行注解
ElementType.METHOD可以给方法进行注解
ElementType.PACKAGE可以给一个包进行注解
ElementType.PARAMETER可以给一个方法内的参数进行注解
ElementType.TYPE可以给一个类型进行注解,比如类、接口、枚举

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
}

@Inherited

一个拥有注解的父类被 @Inherited 注解过,如果它的子类没有被任何注解应用的话,这个子类会继承父类的注解。

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}

@Test
public class A {}
public class B extends A {}

@Repeatable

Java 1.8 新特性。

可以让注解的值同时取多个。

实例

@interface Persons {
    Person[]  value();
}

@Repeatable(Persons.class) //Persons.class 容器注解
@interface Person{
    String role default "";
}

@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan {}

@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。容器注解,就是用来存放其它注解的地方,它本身也是一个注解。

注解的属性

注解的属性也叫成员变量。注解只有成员变量,没有方法!

注解的成员变量在注解的定义中以”无形参的方法“形式来声明,其方法名定义了该成员变量的名字,返回值定义了该成员变量的类型。

TestAnnotation 注解拥有 id 和 msg 两个属性

定义属性时,属性的类型必须是8中基本数据类型 + 类、接口、注解及它们的数组。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    int id(); //属性 id
    String msg(); //属性 msg
}

给注解赋值 id, msg

@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() //可以不加参数,因为有默认值
public class Test {}

如果注解内仅仅有一个名字为 value 的属性时

public @interface Check {
    String value(); //特殊的属性 value
}

// 下面两种方法等同
@Check("hi") //省略了 value=
@Check(value="hi")

若一个注解没有任何属性

public @interface Perform {}

应用这个注解时,可以省略括号

@Perform
public void testMethod(){}

Java预置的注解

@Override

重写父类或接口的方法

@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!");
    }
}

img

可见,say()方法被一条划线标记。

@SuppressWarnings

忽略掉编译器的警告提示。

@SuppressWarnings("deprecation")
public void test1(){
    Hero hero = new Hero();
    hero.say();
    hero.speak();
}

@SafeVarargs

参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。它是在 Java 1.7 的版本中加入的。

@SafeVarargs // Not actually safe!
    static void m(List<String>... stringLists) {
    Object[] array = stringLists;
    List<Integer> tmpList = Arrays.asList(42);
    array[0] = tmpList; // Semantically invalid, but compiles without warnings
    String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
}

上面的代码中,编译阶段不会报错,但是运行时会抛出 ClassCastException 这个异常,所以它虽然告诉开发者要妥善处理,但是开发者自己还是搞砸了。

Java 官方文档说,未来的版本会授权编译器对这种不安全的操作产生错误警告。

@FunctionalInterface

java 1.8 新特性

函数式接口注解,这个是 Java 1.8 版本引入的新特性。函数式编程很火,所以 Java 8 也及时添加了这个特性。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

我们进行线程开发中常用的 Runnable 就是一个典型的函数式接口,上面源码可以看到它就被 @FunctionalInterface 注解。

可能有人会疑惑,函数式接口标记有什么用,这个原因是函数式接口可以很容易转换为 Lambda 表达式。

注解与反射

注意:如果一个注解要在运行时被成功提取,那么 @Rentention(RetentionPolicy.RUNTIME) 是必须的。

基本方法

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {} //判断它是否应用了某个注解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {} //返回指定类型注解
public Annotation[] getAnnotations() {} // 返回注解到这个元素上的所有注解。

实例1

@TestAnnotation()
public class Test {
    public static void main(String[] args) {
        // 注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
        if ( hasAnnotation ) { // 如果获取到的 Annotation 如果不为 null
            // 然后通过 getAnnotation() 方法来获取 Annotation 对象。或者是 getAnnotations() 方法。
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
            System.out.println("id:"+testAnnotation.id()); //id:-1
            System.out.println("msg:"+testAnnotation.msg()); //msg:
        }
    }
}

实例2

@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()); //id:-1
            System.out.println("msg:"+testAnnotation.msg()); //msg:hello
        }
        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()); //check value:hi
            }
            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()); //method testMethod annotation:Perform
                }
            }
        } 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());
        }
    }
}

注解的使用场景

官方文档描述

注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。

注解有许多用处,主要如下:

  • 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息。
  • 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
  • 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取。
    值得注意的是,注解不是代码本身的一部分。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值