Java基础之注解

注解

其实注解就是注释的意思。我想这样叫法是跟平时用的注释不一样吧。

Java内置了三种注解,想必都见过。

    @Override
    @Deprecated
    @SuppressWarnings

好奇的小伙子,会点击进去一探究竟。发现又一批注解。

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }

继续点击又会发现Target、Retention、Documented注解互相出现。这三个加上Inherited称为元注解。即注解的注解。这有点绕,其实就是用来声明注解的东西。那四个都代表什么意思呢。

元注解

Target注解指示注释类型所适用的程序元素的种类。先来看看Target内部,省去上边的注解,它跟接口不同就是interface前面加个@。注解都是这个模样。内部的方法也称为成员。Target里边有ElementType枚举数组成员,分别表示不同的作用领域。

    ...
    public @interface Target {//被标记为Target名的注解
        ElementType[] value();//成员
    }

    public enum ElementType {
        TYPE, //类、接口(包括注释类型)或枚举声明
        FIELD, //字段声明(包括枚举常量)
        METHOD, //方法声明
        PARAMETER, //参数声明
        CONSTRUCTOR, //构造方法声明
        LOCAL_VARIABLE, //局部变量声明
        ANNOTATION_TYPE, //注释类型声明
        PACKAGE //包声明
    }

Retention注解指示注释类型的注释要保留多久。内部的成员是RetentionPolicy枚举。分别表示不同生命周期。比如Override、Deprecated、SuppressWarnings注解都属于SOURCE类型,用完就丢。RUNTIME类型将会保存注解,因此可以反射性地读取,也是我们自定义注解用到的。

    ...
    public @interface Retention {
        RetentionPolicy value();
    }

    public enum RetentionPolicy {
        CLASS, //编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。
        RUNTIME, //编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
        SOURCE//编译器要丢弃的注释。
    }

剩下的DocumentedInherited注解都是没有成员。Documented注解指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。Inherited注解指示注释类型被自动继承。用的也不多,就不深入了。

    public @interface Documented {
    }

    public @interface Inherited {
    }

自定义注解

自定义注解至少使用Target注解和Retention注解。首先创建一个接口,在interface前面加一个@。同时声明Target注解和Retention注解。

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

    //声明在类名上面
    @TargetType
    public class Person {

            @TargetType //报错,声明地方不对
            private String name;
    }

声明不同的地方,就需要另外创建注解。

    @Target(ElementType.FIELD)//指定字段
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TargetField {
    }

    @Target(ElementType.METHOD)//指定方法
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TargetMethod {
    }

    //以下使用正确无误
    @TargetType
    public class Person {

        @TargetField
        private String name;

        @TargetMethod
        public void printName(){
            System.out.println(name);
        }
    }

没有成员的注解,相当是一个标识。使其让注解丰富起来,可以加上成员。在接口内部加上方法,可以指定默认值。没有指定默认值,那就是必填,不然会报错。要注意的是成员只支持基本类型、String及枚举类型。

    public @interface TargetField {
        String name() default "无名";
        int age();
    }

    @TargetField(name= "name",age=18)
    private String name;

只有一个成员,直接使用value方法,可以省略xxx=。

    public @interface TargetField {
        String value();
    }

    //对应value  不需要写xxx==
    @TargetField("name")
    private String name;

注解处理

注解是标识了代码,但是没卵用啊。的确是这样,处理它们之前是真的没什么用。注解永远不会改变被注解的代码的语义,但是它可以通过工具进行特殊的处理。Class类下会有一些getDeclaredXXX的方法,表示反映此 Class 对象所表示的类或接口所声明的所有XXX。相对应的Field、Method、Constructor都有getAnnotation方法获取注解类。

这里写图片描述

    Class cls = Person.class;

    Field[] fields = cls.getDeclaredFields();//获取字段
    for (Field f : fields) {
        if (f.isAnnotationPresent(TargetField.class)) {//判断是否存在注解类
            TargetField targetField = f.getAnnotation(TargetField.class);//获取注解类
            String value = targetField.value();//取出属性  name
        }
    }

获取被注解的方法也差不多,要是直接调用方法会报错,要先把方法为static修饰才可以。

        Method[] methods = cls.getDeclaredMethods();
        for (Method m : methods) {
            if (m.isAnnotationPresent(TargetMethod.class)) {
                try {
                    m.invoke(null);
                } catch (IllegalAccessException e) {
                } catch (IllegalArgumentException e) {
                } catch (InvocationTargetException e) {
                }
            }
        }

总的来说,注解并不难,只是被注解是一种标识,也可以取属性值。掌握注解就很多玩法了,配置处理应用注解比较多。不足之处请指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值