Java注解和自定义注解知识点整理

1. 注解介绍

从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。

简单来说,注解就是代码的一个标记,当某段代码添加了这个标记之后,这段代码就有了一个额外的信息。
比如说toString这个方法有个@Override,就表明了这个方法是重写方法,这个就是额外的信息。

class Test{
    @Override
    public String toString() {
        return super.toString();
    }
}
  • 注解不影响原有的代码逻辑(Override标签并不会影响其方法的实际内容)。
  • 注解也可以有实际的代码实现,而不仅仅是信息描述。

1.1 和注释的区别

简单来说,注释和注解一样,都是代码的辅助信息,只是对象不同。

注释是给人看的,也就是给我们编程者看的,我们肉眼可以识别各种各样的内容,所以注释自然是写中文英文什么文都无所谓。

而注解是给编译器看的,编译器只能识别代码,所以在写注解的时候就只能写约定好的代码。

1.2 注解的本质

注解的本质是一个接口,以Override为例,Override接口的实际内容是这样的。

package java.lang;

import java.lang.annotation.*;  //注意这个引用的包,里面就有注解相关的类

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

而这个东西实际上就是

public interface Override extends Annotation{
}

2. 如何自定义一个注解

  1. 通过@interface创建一个注解。

    public @interface test {
    }
    
  2. 使用一个对象(这里用的是类)添加这个注解。

    @test
    public class AnnotationDemo {
    }
    
  3. 注解也可以添加参数。

    public @interface test2 {
        String value(); //这里就表示了添加的参数是String类型
    }
    
  4. 这个时候再使用注解的时候就必须要加入相关参数

    @test
    @test2("aaa")
    public class AnnotationDemo {
    }
    
  5. 加上default关键字可以有个默认值。

    public @interface test2 {
        String value() default "11";
    }
    

3. 已存在的注解

3.1 基本注解

也就是Java自己内置的注解,介绍几个常见的。

  • @Override重写方法:当子类重写了父类的同名方法时,可以加上这个注解,避免自己在编写代码的时候出现一些意外的低级错误,当然你不加也不会影响运行。

    class Test{
        @Override //表示是继承方法,继承的是Object类的toString
        public String toString() {
            return super.toString();
        }
    }
    
  • @Deprecated过时方法:加上这个注解后表示这个方法已经过时了,建议使用效果相同甚至更好的新版方法,当我们编程者使用这个方法的时候,一般都会有一个删除线。
    在这里插入图片描述

  • @SuppressWarnings忽略警告:当代码的某处有不合理时,就会出现各种各样的警告,这一部分的代码一般会标上黄底或者字体为灰色,如果不想看到它的话,加上这个标签就好。
    在这里插入图片描述
    加入注解后,fun1的never uesd不提示了(不再是灰色底),然后this != null的always true也不提示了。
    在这里插入图片描述

3.2 元注解

元注解简单来说就是对注解的注解,为注解本身添加特性。还以Override为例

package java.lang;

import java.lang.annotation.*;  //注意这个引用的包,里面就有注解相关的类

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

上面的@Target和@Retention就是元注解,它们都在annotation这个包内。
在这里插入图片描述
元注解有以下几种。

  • @Retention:表明了注解的声明周期,只能取声明好的值。

    • RetentionPolicy.SOURCE,该注解只在源码阶段保留,编译的时候丢弃。
    • RetentionPolicy.CLASS,该注解会保留到编译的过程中,但不会加载到JVM中。
    • RetentionPolicy.RUNTIME,该注解最终会加载到JVM中。
  • @Target:表明了目标注解的作用范围(如类,方法等)。

    描述
    ElementType.TYPE允许注解使用在类,接口和枚举上
    ElementType.FIELD允许注解使用在属性字段上
    ElementType.METHOD允许注解使用在方法上
    ElementType.PARAMETER允许注解使用在方法参数上
    ElementType.CONSTROCTOR允许注解使用在构造方法上
    ElementType.LOCALVARIABLE允许注解使用在本地变量上
    ElementType.ANNOTATION_TYPE允许注解使用在注解上
    ElementType.PACKAGE允许注解使用在包名上
    ElementType.TYPE_PARAMETER允许注解使用在类型参数上(JDK1.8加入)
    ElementType.TYPE_USE允许注解使用在任何类型上(JDK1.8加入)
  • @Inherited:表明这个注解是可以在类中继承的。如果
    1. 一个类没有任何注解且拥有父类。
    2. 它的父类的注解中有Inherited注解。
    那么,这个类也会拥有这个注解。举个例:

    @Inherited
    public @interface test {
    }
    
    
    @test
    class A{}
    
    
    class B extends A{}
    

    这个时候B没有任何注解,那么它此时就会有test这个注解。

  • @Documented:和文档相关,表示被注解的元素可以写到JAVADOC中。

  • @Repeatable:1.8后加入,表示这个注解可以重复使用元素,这个不太好理解。
    举个例子:

    public @interface test2 {
        String value();
    }
    
    @test2("aaa")
    @test2("bbb")
    @test2("ccc")
    class A {}
    

    在之前是不能实现的,会报错。在引用Repeatable后,配合另一个注解就可以实现了。

    @Repeatable(test4.class)
    public @interface test2 {
        String value();
    }
    
    //用另一个注解来包装原先注解的集合
    @interface test4{
        test2[] value();
    }
    
    @test2("aaa")
    @test2("bbb")
    @test2("ccc")
    class A{}
    

4. 注解的实际使用

注解本身不能实现任何功能,需要搭配自己编写的代码来实现其内容,而这些实现的代码一般叫做APT(Annotation Processing Tool)。

之前说注解是给编译器看的,实际上就是给这个APT看的,只是这个APT也要我们自己来写。

然后APT的代码一般都会使用反射,所以注解本身也是搭配反射来使用的,接下来的内容需要对反射有基本的了解才好看。

示例:调用一个类中只添加test注解的方法。

  1. 先写一个test注解,由于已经了解了元注解,所以要加上Retention和Target。

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD) //由于是检测方法,所以这里写Method
    public @interface test {
    }
    
  2. 搞一个类,一部分方法添加@test,一部分不加。

    class A {
        @test
        public void fun(){
            System.out.println("fun");
        }
    
        public void fun2(){
            System.out.println("fun2");
        }
    }
    
  3. 最后调用,要用上反射。

    public class AnnotationDemo {
        public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
            A a = new A(); 
            Class classA = a.getClass();
            Method[] methods = classA.getMethods(); //这三步获取了方法的列表
            
            for (Method method: methods){
                if (method.isAnnotationPresent(test.class))  //检查是否有添加test注解
                    method.invoke(a); //有的话就调用
            }
        }
    }
    
    

参考材料

java注解-最通俗易懂的讲解 - Tanyboye的博客 - CSDN博客
https://blog.csdn.net/qq1404510094/article/details/80577555
JAVA 注解的基本原理 - Single_Yam - 博客园
https://www.cnblogs.com/yangming1996/p/9295168.html
注解(java注解)_百度百科
https://baike.baidu.com/item/%E6%B3%A8%E8%A7%A3/22344968?fromtitle=Annotation&fromid=10645762&fr=aladdin
Java 8 Repeatable注解的使用 - 软件工程实践者 - BlogJava
http://www.blogjava.net/robin/archive/2016/09/06/431753.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值