前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >解读Java 注解 (Annotation)

解读Java 注解 (Annotation)

作者头像
每天学Java
发布2020-06-01 17:02:55
6130
发布2020-06-01 17:02:55
举报
文章被收录于专栏:每天学Java每天学Java

Annotation中文意思就是注解的意思,在 Java 中注解是一个很重要的知识点,但是理解Annotation以及怎么运用,你是否真的明白?

01

Annotation

在平时工作中,使用注解应该是很常见的事情。但是对于注解你是否真正的去了解呢?下面我们一起来看一下如何去使用注解。

注解有什么用?Java 注解用于为 Java 代码提供元数据。不知道大家对于这句话是否理解,什么叫为Java代码提供元数据,我在一篇博客上看到一个非常通俗的解释:标签。注解就是对于代码中某些鲜活个体的贴上去的一张标签,也就是将一些对象使用注解的时候,可以理解为该对象被贴上一个标签。

知道注解的作用之后,我们来看一下注解的定义和使用:

1.定义注解:注解通过@interface 关键字进行定义。

代码语言:javascript
复制
@interface AnnotationExample {

}

2.注解的使用:

代码语言:javascript
复制
@AnnotationExample()
public class StudyAnnotation {

}

这里我们就定义来一个空的注解,和使用注解的类,那么如何让注解生效呢?那就需要提到元注解了,元注解是一种基本的注解,它能够应用到其它的注解上面。意思就是元注解是使用在注解上面的,也就是在AnnotationExample上面使用。元注解有哪些 呢?

元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

那么这5种元注解如何使用呢?

@Retention

Retention是保留期的意思,它解释说明了这个注解的的存活时间。

它有3种可使用的值:

代码语言:javascript
复制
-RetentionPolicy.SOURCE  注解只在源码阶段保留,在编译器进行编译时它
将被丢弃忽视。

-RetentionPolicy.CLASS  注解只被保留到编译进行的时候,它并不会被加载到
JVM 中。

-RetentionPolicy.RUNTIME  注解可以保留到程序运行的时候,它会被加载进入
到 JVM 中,所以在程序运行时可以获取到它们。

通常我们会使用RetentionPolicy.RUNTIME这样注解的存活时间最久

@Documented

它的作用是能够将注解中的元素包含到 Javadoc 中去。什么意思呢?它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。

@Target

指定了注解运用的地方。你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。它有如下可选值

代码语言:javascript
复制
 ElementType.ANNOTATION_TYPE  可以给一个注解进行注解
 ElementType.CONSTRUCTOR  可以给构造方法进行注解
 ElementType.FIELD  可以给属性进行注解
 ElementType.LOCAL_VARIABLE  可以给局部变量进行注解
 ElementType.METHOD   可以给方法进行注解
 ElementType.PACKAGE  可以给一个包进行注解
 ElementType.PARAMETER  可以给一个方法内的参数进行注解
 ElementType.TYPE  可以给一个类型进行注解,比如类、接口、枚举

@Inherited

Inherited 是继承的意思,什么意思呢?如果一个类使用了拥有Inherited的注解,如果它的子类没有被任何注解应用的话,那么这个子类就继承了该类的注解。

@Repeatable

Repeatable是可重复的意思。@Repeatable 是 Java1.8加进来的,所以算是一个新的特性。 换句话说就是,可以多次使用被Repeatable修饰的注解,一个人可以有很多身份,类也一样,通过注解要表示它多个身份的时候,我们就需要用Repeatable

代码语言:javascript
复制
@interface Persons {
    Identity[]  identity();
}


@Repeatable(Persons.class)
@interface Identity{
    String identity default "";
}


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

}

到这里我们就已经大致的了解注解是什么,那么如何去使用注解呢?

02

注解的使用

我们通过一个实例来看如何运用注解吧(希望大家能发散思维去想如何运用注解,不只是停留在我所举的例子中)。

假如我有一个接口,而接口下面有两个实现类,我想通过注解实现在不同情况下去去调用这两个实现类(可以运用到策略模式上面)。

现在我们来定义一个注解

代码语言:javascript
复制
@interface AnnotationExample {
 int Identity() default 0;
}

这个注解中Identity默认是0,现在我们要定义一个接口和两个实现类,同时在实

现类上加上这个注解

代码语言:javascript
复制
interface inter{
    void printInfo();
}
@AnnotationExample(Identity = 1)
class interImp implements inter{

    @Override
    public void printInfo() {
        System.out.println("欢迎大家关注每天学Java公众号,这里每天都有文章推送(应该每天都会有吧,嘿嘿)");
    }
}
@AnnotationExample(Identity = -1)
class interImp1 implements inter{

    @Override
    public void printInfo() {
        System.out.println("欢迎大家进入每天学Java小程序,这里每天都有题库更新(应该每天都会有吧,嘿嘿)");
    }
}

注解定义了,接口也定义了,实现类也是使用了注解,那么接下来我们要做什么呢?

既然是根据注解来区别不同的实现类,那么首先我们要获取到这个注解下面有多少类使用类它(用到了反射)。关于API这里就不介绍了,大家私下去看,直接上代码。

首先说明一下,注解的API一般都是Class 对象作为参数,所以我们首先需要拿到class文件。

代码语言:javascript
复制
class MainTest2 {
    //存放class 文件集合
    private static List<Class<? extends inter>> list;
    //获取类加载器
    private ClassLoader classLoader = 
    getClass().getClassLoader();

    //获取扫描的包下面所有的class文件
    private File[] getResources() {
        try {
            //我这里 src 目录下没有建包,可以直接使用getResource("")
            //如何有包,getResource(包名字.replace(".", "/"))
            File file = 
            new File(classLoader.getResource("").toURI());
            return file.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                //只取class文件
                    if (pathname.getName().endsWith(".class")) {//我们只扫描class文件

                        return true;
                    }
                    return false;
                }
            });
        } catch (URISyntaxException e) {
            throw new RuntimeException("未找到策略资源");
        }
    }

    //拿到class文件后,我们要找到使用这个注解的实现类
    public void getImpClass() throws ClassNotFoundException {
        list = list = new ArrayList<Class<? extends inter>>();
        File[] resources = getResources();
//        System.out.println(resources.length);
        //使用相同的加载器加载实现类的接口
        Class<inter> interClass = (Class<inter>) classLoader.loadClass(inter.class.getName());
        for (int i = 0; i < resources.length; i++) {
            try {
                //载入包下的类
                Class<?> clazz = classLoader.loadClass(resources[i].getName().replace(".class", ""));
//                System.out.println(i);
                //判断是否是inter的实现类并且不是它本身,满足的话加入到策略列表
                if (inter.class.isAssignableFrom(clazz) && clazz != interClass) {
//                    System.out.println(i);
                    list.add((Class<? extends inter>) clazz);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

    }

    //处理注解,我们传入一个实现类,返回它的注解
    private static AnnotationExample handleAnnotation(Class<? extends inter> clazz) {
        Annotation[] annotations = clazz.getAnnotations();
        if (annotations == null || annotations.length == 0) {
            return null;
        }
        for (int i = 0; i < annotations.length; i++) {
            if (annotations[i] instanceof AnnotationExample) {
                return (AnnotationExample) annotations[i];
            }
        }
        return null;
    }

    //开始区分
    public void ide() {
        for (Class<? extends inter> claszz : list) {
            AnnotationExample annotationExample = handleAnnotation(claszz);
            System.out.println(annotationExample.Identity());
            if (annotationExample.Identity() == 1) {
                try {
                    claszz.newInstance().printInfo();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public static void main(String[] args) throws ClassNotFoundException {
        MainTest2 mainTest2 = new MainTest2();
        mainTest2.getImpClass();
        mainTest2.ide();
    }
}

通过annotationExample.Identity() == 1这一行,我们可以把这个1作为参数进行传入,然后通过注解就可以获取到不同的实现类的实例,这样我们就能通过注解来区分不同的实现类,达到我们想要的目的。


今天小程序更细题库:进入小程序

1.什么是元数据(metadata)

2.什么是注解(Annotation)?

3.数据的加密模式?加密模式的顺序?

4.post和get以及get和load的区别?使用get应注意什么?

5.Java 类加载器都有哪些

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天学Java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档