Java-注解

前言

在JavaSE中,注解的使用目的比较简单,例如标记过时的功能、抑制警告等等。在JavaEE中,注解占据了更重要的角色,现在流行框架Spring... Mybatis等都支持注解开发

1、注解使用示例

Java中有很多注解,我们举例三个常见的注解

1.1、@Override

作用域:只能写在方法上

含义:表示这个方法是重写的父类的方法

重写了父类的方法,如果添加上这个注解,那么重写的方法如果方法名称错误或者返回值类型错误,编译就会报错提示,反之没加注解,则不会提示

案例(观察sayHi3、sayHi4方法,都想要重写sayHi2方法,但是方法名都写错了,查看结果)

package com.tcc.entity;

import java.io.Serializable;

/**
 * @author 宇辰
 * @date 2022/9/26-11:27
 **/
public class User extends Person {

    public static void main(String[] args) {
        User user = new User();
        user.sayHi(); // 我是用户
    }

    @Override
    public void sayHi() {
        System.out.println("我是用户");
    }

    @Override
    public void sayHi3() {
        System.out.println("想要重写父类方法sayHi2");
    }

    public void sayHi4() {
        System.out.println("想要重写父类方法sayHi2");
    }
}

class Person {
    private String name;
    private String sex;

    public void sayHi(){
        System.out.println("我是人");
    }

    public void sayHi2(){
        System.out.println("被重写的方法");
    }
}

结果(可以看到带注解的会报错,因为在父类中没有找到被重写的方法sayHi3)

在这里插入图片描述

1.2、@Deprecated

作用域:只能写在方法上

含义:表示这个方法已经过时,不建议使用,但仍可以使用

被这个注解描述过的方法,调用的时候会在上面会显示被划掉的特殊样式

案例(Date日期类型很多方法都过时了)

在这里插入图片描述

调用结果

在这里插入图片描述

1.3、@SuppressWarnings

作用域:可以写在任何位置,类、方法、属性…等

含义:抑制编译器的警告,不提示警告消息

参数

  • 抑制单类型警告@SuppressWarnings(“unchecked”)、
    抑制多类型警告@SuppressWarnings(“unchecked”,“rawtypes)、
    抑制所有类型警告:@SuppressWarnings(“all”)
  • all: 抑制所有警告
  • boxing :抑制装箱、拆箱操作时候的警告
  • cast: 抑制映射相关的警告
  • dep-ann: 抑制启用注解的警告
  • deprecation: 抑制过期方法警告
  • fallthrough: 抑制在 switch 中缺失 breaks 的警告
  • finally :抑制 finally 模块没有返回的警告
  • hiding: 抑制相对于隐藏变量的局部变量的警告
  • incomplete-switch: 忽略不完整的 switch 语句
  • nls: 忽略非 nls 格式的字符
  • null :忽略对 null 的操作
  • rawtypes: 使用 generics 时忽略没有指定相应的类型
  • restriction: 抑制禁止使用劝阻或禁止引用的警告
  • serial: 忽略在 serializable 类中没有声明 serialVersionUID 变量
  • static-access: 抑制不正确的静态访问方式警告
  • synthetic-access: 抑制子类没有按最优方法访问内部类的警告
  • unchecked: 抑制没有进行类型检查操作的警告
  • unqualified-field-access : 抑制没有权限访问的域的警告
  • unused: 抑制没被使用过的代码的警告

使用Eclipse的话,如果参数定义了没使用,会有个黄色警告。

使用Idea的话,则是参数名称颜色变灰,都表示一个意思,警告

没有被使用,并且没有添加注解

没有被使用,但是使用了注解

在这里插入图片描述

2、自定义注解

注解一般在反射机制中用的多

  • 定义新的Annotation类型使用@interface关键字
  • 自定义注解自动继承了java.lang.annotation.Annotation接口
  • Annotation的成员变量在Annotation定义中以无参数方法的形式来生命,其方法名和返回值定义了该成员的名字和类型。。我们成为配置参数。类型只能是八种基本数据类型:String、Class、Enum、Annotation以上所有类型的数组。
  • 可以在定义Annotation的成员变量是为其指定初始值,指定成员变量的初始值可使用default关键字
  • 如果只有一个参数成员,建议使用参数名为value
  • 如果定义的注解含有配置参数,那么使用时必须指定参数值,除非有默认的值,格式是:参数名=参数值,如果只有一个参数成员,且名称为value,则可以省略value=,直接写值
  • 没有成员定义的Annotation成为标记,包含成员变量的注解称为元数据注解

自定义注解必须配上注解的含义才有意义(在注解上写文档注解表名该注解含义)

无参注解


定义

package com.tcc.anno;

/**
 * @author 宇辰
 * @date 2022/9/26-11:27
 **/
public @interface MyAnno {

}

使用

在这里插入图片描述

有参注解


定义

package com.tcc.anno;

/**
 * @author 宇辰
 * @date 2022/9/26-11:27
 **/
public @interface MyAnno {

    String value();

    // 有默认值的注解,有默认值的话,使用注解可以不写该参数的值
    //String value() default "demo";
}

使用

在这里插入图片描述

3、元注解

元注解是定义在注解上的注解,用于修饰其他注解

JDK5.0提供了4个标准的meta-annotation类型,分别是:

  • Retention:指定该注解的生命周期
  • Target:指定该注解使用的地方
  • Documented:指定是否在JavaDoc文档中显示
  • Inherited:指定子类是否继承父类的这个注解

3.1、Retention注解

只能用于修饰一个Annotation定义,用于指定该Annotation的生命周期,@Retention包含一个@RetentionPolicy类型的成员变量,使用@Rentention时,必须为该value成员变量指定值

  • RetentionPolicy.SOURCE:在源文件中有效(即源文件中保留),编译器直接丢掉这种策略的注解
  • RetentionPolicy.CLASS(默认):在class文件中保留(即编译文件中保留),当运行Java程序时,JVM不会保留注解
  • RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行Java程序时,JVM会保留注解,程序可以通过反射来获取该注解

下面分别举例

SOURCE


  1. 在自定义注解上,添加该注解,并且参数为RetentionPolicy.SOURCE

    package com.tcc.anno;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    /**
     * @author 宇辰
     * @date 2022/9/26-11:27
     **/
    @Retention(RetentionPolicy.SOURCE)
    public @interface MyAnno {
    }
    
  2. 把注解写到main方法上

    在这里插入图片描述

  3. 运行main方法,查看编译后的文件是否保留了该注解(并没有保留)

    在这里插入图片描述

CLASS


  1. 在自定义注解上,添加该注解,并且参数为RetentionPolicy.CLASS

    package com.tcc.anno;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    /**
     * @author 宇辰
     * @date 2022/9/26-11:27
     **/
    @Retention(RetentionPolicy.CLASS)
    public @interface MyAnno {
    }
    
  2. 把注解写到main方法上

  3. 运行main方法,查看编译后的文件是否保留了该注解(保留了)

    在这里插入图片描述

RUNTIME


  1. 在自定义注解上,添加该注解,并且参数为RetentionPolicy.RUNTIME

  2. 把注解写到自定义的实体类上

    package com.tcc.entity;
    
    import com.tcc.anno.MyAnno;
    
    /**
     * @author 宇辰
     * @date 2022/10/22-14:09
     **/
    @MyAnno
    public class User {
        private String name;
        private String sex;
    
    
    }
    
    
  3. Main方法中,使用反射获得该注解(只有值为RUNTIME的才可以使用反射获取注解)

    package com.tcc.test;
    
    
    import com.tcc.anno.MyAnno;
    import com.tcc.entity.User;
    
    /**
     * @author 宇辰
     * @date 2022/8/31-8:53
     **/
    public class Test {
        public static void main(String[] args){
            Class<User> userClass = User.class;
            MyAnno annotation = userClass.getAnnotation(MyAnno.class);
            System.out.println(annotation.toString()); // @com.tcc.anno.MyAnno()
        }
    }
    

3.2、Target注解

用于修饰Annotation定义,用于指定被修饰的Annotation能用于修饰那些程序元素

@Target也包含一个名为value的成员变量,参数类型为ElementType的枚举类

ElementType

参数有很多,这里就不一一讲解, 这里只演示ElementType.METHOD,作用在方法上

package com.tcc.test;


import com.tcc.anno.MyAnno;
import com.tcc.entity.User;

/**
 * @author 宇辰
 * @date 2022/8/31-8:53
 **/
// @MyAnno  写在类上,报错
public class Test {

    @MyAnno // 只能写在方法上面
    public static void main(String[] args){
        Class<User> userClass = User.class;
        MyAnno annotation = userClass.getAnnotation(MyAnno.class);
        System.out.println(annotation.toString()); // @com.tcc.anno.MyAnno()
    }
}

3.3、Documented注解

表明该注解是否显示在生成的JavaDoc文档中,没有参数,用作标识

默认情况下JavaDoc是不包括注解的

举例


在这里插入图片描述

如何生成JavaDoc文档


在这里插入图片描述

3.4、Inherited注解

被它修饰的Annotation将具有继承性,如果某个类使用了被@Inherited修饰的Annotation,则其子类自动具有该注解

举例


  1. 在自定义注解上添加该注解

    package com.tcc.anno;
    
    import java.lang.annotation.*;
    
    /**
     * @author 宇辰
     * @date 2022/9/26-11:27
     **/
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @Documented
    @Inherited
    public @interface MyAnno {
    }
    
  2. 在实体类(User)中使用该注解

    package com.tcc.entity;
    
    import com.tcc.anno.MyAnno;
    
    /**
     * @author 宇辰
     * @date 2022/10/22-14:09
     **/
    @MyAnno
    public class User {
        private String name;
        private String sex;
    
    }
    
  3. 在Main方法所在的类(Test)中继承User实体类,然后使用反射获取(Test)类上的注解

    package com.tcc.test;
    
    
    import com.tcc.anno.MyAnno;
    import com.tcc.entity.User;
    
    /**
     * @author 宇辰
     * @date 2022/8/31-8:53
     **/
    public class Test extends User {
        public static void main(String[] args){
            Class<Test> testClass = Test.class;
            MyAnno annotation = testClass.getAnnotation(MyAnno.class);
            System.out.println(annotation.toString()); // @com.tcc.anno.MyAnno()    因为继承了User类,这个类上有MyAnno注解,所以它自己也有
        }
    }
    

4、JDK8新特性(可重复注解)

@Repeatable(MyAnnos.class)里面参数使用自己定义的注解

准备

在一个地方重复使用两次注解,查看结果(会报错)


在这里插入图片描述

4.1、JDK8之前解决办法

思路:

​ 创建一个注解,参数为想重复写的注解数组,然后在想要写的地方使用该注解,参数填入注解数组即可实现写多个重复注解

  1. 创建一个MyAnnos注解,定义类型为MyAnno数组的参数

    package com.tcc.anno;
    
    /**
     * @author 宇辰
     * @date 2022/10/22-15:34
     **/
    public interface MyAnnos {
        MyAnno[] value();
    }
    
    
  2. User类上使用MyAnnos注解,参数传入两个相同的MyAnno注解

    package com.tcc.entity;
    
    import com.tcc.anno.MyAnno;
    import com.tcc.anno.MyAnnos;
    
    /**
     * @author 宇辰
     * @date 2022/10/22-14:09
     **/
    /*@MyAnno("test1")
    @MyAnno("test2")*/
    @MyAnnos({@MyAnno("test1"),@MyAnno("test2")})
    public class User {
        private String name;
        private String sex;
    
    }
    
    

4.2、JDK8解决办法

使用注解:@Repeatable(MyAnnos.class)

注意:

  • 参数里面自定义的注解的元注解,要与里面的参数里面的注解的元要保持一致,即子有,父也要有
  • 作用域可以不保持一致,但是一定要比参数注解的生命周期长
  1. 使用我们上面定义的MyAnnos注解

    package com.tcc.anno;
    
    /**
     * @author 宇辰
     * @date 2022/10/22-15:34
     **/
    public @interface MyAnnos {
        MyAnno[] value();
    }
    
    
  2. 在需要重复使用的注解上面添加:@Repeatable(MyAnnos.class)注解即可

    package com.tcc.anno;
    
    import java.lang.annotation.*;
    
    /**
     * @author 宇辰
     * @date 2022/10/22-15:34
     **/
    // 因为参数注解也有这些属性,所以父注解也需要有
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @Documented
    @Inherited
    public @interface MyAnnos {
        MyAnno[] value();
    }
    
    
  3. 使用

    package com.tcc.entity;
    
    import com.tcc.anno.MyAnno;
    
    /**
     * @author 宇辰
     * @date 2022/10/22-14:09
     **/
    @MyAnno("test1")
    @MyAnno("test2") // 不报错了
    //@MyAnnos({@MyAnno("test1"),@MyAnno("test2")})
    public class User {
        private String name;
        private String sex;
    
    }
    
    

5、JDK8新特性(类型注解)

在Java8中,ElementType新增了两个值

  • TYPE_PARAMETER:作用在类型参数上( 比如:泛型)
  • TYPE_USE:作用在类型上(包含上面那个)

举例


  1. 修改MyAnno注解上的@Target元注解参数

    package com.tcc.anno;
    
    import java.lang.annotation.*;
    
    /**
     * @author 宇辰
     * @date 2022/9/26-11:27
     **/
    @Retention(RetentionPolicy.CLASS)
    @Target(ElementType.TYPE_USE)
    @Documented
    @Inherited
    public @interface MyAnno {
    }
    
  2. 使用

    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值