Java - 注解的使用

  • Java基本内置注解

    • @Override

      • @Override用在方法上,表示这个方法重写了父方法,如toString()

      • 如果父方法没有这个方法,那麽就无法编译过

      • 如果实现接口,需要在每个实现方法都加上@Override,说明这是要实现那个接口的方法,而不是自己新创的方法

    • @Deprecated

      • @Deprecated 表示这个方法已经过期,不建议开发者使用

      • 暗示在将来某个不确定的版本,就有可能会被取消掉

    • @SuppressWarnings

      • @SuppressWarnings是抑制警告的意思,这个注解主要的用处就是忽略警告信息

      • 常见的警告值

        • deprecation : 使用了不赞成使用的类或方法时的警告

        • unused : 某个变量被定义,但是没有被使用

        • path : 在类路径、源文件路径等中有不存在的路径时的警告

      • 具体实例

        public class Test {
            //定义了一个不建议使用了方法
            @Deprecated
            public void sayHello() {
                System.out.println("Hello");
            }
        
            //声明以下的方法,自动忽略deprecation和unused的警告,不要在console上报出warn
            //以下的方法使用了被Deprecated的方法sayHello
            //也没有使用到一个被定义的变量 i
            //但是因为设置了警告忽略所以不会有warning
            @SuppressWarnings({"deprecation", "unused"})
            public static void main(String[] args) {
                int i;
                Test test = new Test();
                test.sayHello();
            }
        }
    • @FunctionallInterface

      • Java 1.8新增的注解,用于约定函数式接口

      • 函数式接口概念

        • 函数式接口存在的意义,主要是配合Lambda表达式来使用

        • 如果接口中只允许有一个public的抽象方法,该接口就称为函数式接口 (不过此接口可以包含多个default方法或是多个static方法)

          • 能够包含多个default和static方法的原因是因为在使用函数式编程时,为了能够使用lambda表达式,所以每个接口的实现类只允许实现一个方法

          • 而default方法和static方法不允许实现类实现,所以就不会影响lambda表达式,因此就可以存在在函数式接口裡

          //匿名实现类 new Function<Integer, String> 实现了Function接口
          List<Integer> intList = Lists.newArrayList(1, 2, 3);
          List<String> stringList = Lists.transform(intList, new com.google.common.base.Function<Integer, String>() {
              @Override
              public String apply(Integer input) {
                  return input + "aa";
              }
          });
          
          //可以转换成下面的lambda表达式
          List<Integer> intList = Lists.newArrayList(1, 2, 3);
          List<String> stringList = Lists.transform(intList, input -> input + "aa");
      • 使用 @FunctionallInterface 自定义函数式接口

        //自定义一个函数式接口,并且只有一个public的抽象方法
        @FunctionalInterface
        public interface MyFunction {
            public String myApply();
        }
        
        //定义一个类,让这个类去使用 MyFunction
        public class Hello {
            void say(MyFunction myFunction) {
                System.out.println(myFunction.myApply());
            }
        }
        
        public class MainTest {
            public static void main(String[] args) {
                Hello hello = new Hello();
                
                //输出 Hello World
                hello.say(new MyFunction() {
                    @Override
                    public String myApply() {
                        return "Hello World";
                    }
                });  
                
                //可以转换为以下的lambda表达式,同样输出 Hello World
                hello.say(() -> "Hello World");
            }
        }
  • 自定义新的注解

    • 使用元注解(meta annotation)来设定一个注解的作用,可以说他是 "自定义注解" 的注解

    • 元注解的种类

      • @Target : 表示这个注解可以放在什麽位置上,也就是可以修饰

        • ElementType.TYPE : 能修饰类、接口、枚举、注解

        • ElementType.FIELD : 能修饰字段、枚举的常量

        • ElementType.METHOD : 能修饰方法

        • ElementType.PARAMETER : 能修饰方法参数

        • ElementType.CONSTRUCTOR : 能修饰构造函数

        • ElementType.LOCAL_VARIABLE : 能修饰局部变量

        • ElementType.ANNOTATION_TYPE : 能修饰注解 (元注解就是此种)

        • ElementType.PACKAGE : 能修饰包

      • @Retention : 表示这个注解的生命週期

        • 可选的值有三种

          • RetentionPolicy.SOURCE

            • 表示此注解只在源代码中有效果,不会编译进class文件

            • @Override就是这种注解

          • RetentionPolicy.CLASS

            • 表示此注解除了在源代码有效果,也会编译进class文件,但是在运行期是无效果的

            • @Retention的默认值,即是当没有指定@Retention的时候,就会是这种类型

          • RetentionPolicy.RUNTIME

            • 表示此注解从源代码到运行期一直存在

            • 程序可以透过反射获取这个注解的信息

      • @Inherited : 表示该注解有继承性,即是子类可以拿到继承父类上的注解信息

      • @Documetned : 在用javadoc命令生成API文档后,文档裡会出现该注解说明

      • @Repeatable (java1.8新增)

        • 当没有使用@Repeatable修饰的时候,注解在同一个位置只能出现一次,如果写重複的两次就会报错

        • 但是使用@Repeatable之后,就能够在同一个地方使用多次

        • 使用@Repeatable的时机通常在想要取得一组资讯时

          • 像是一个User裡面可能有id、name属性,我们想要以User为单位来取

          • 但是因为注解裡面无法使用自定义对象

          • 所以只能透过@Repeatable这种方法来达成目标

    • 注解参数的数据类型

      • 支持的类型

        • 所有基本数据类型(int, float, boolean, byte, double, char, long, short)

        • String类型

        • Class类型

        • enum类型

        • Annotation类型

        • 以上所有类型的数组

      • 不支持的类型

        • 自定义对象

    • 注解参数

      • 可以使用default来自定义某个参数的默认值

      • 如果注解裡面只有一个参数value(名字很重要,只能用这个名字),或是其他参数值都有default设定,这时使用此注解时可以不用打参数值,例如 @GetMapping("/")

    • 具体实例

      • 如何使用一个自定义的注解

        //自定义注解 MyAnnotaion,使用 @interface 定义他是一个注解
        @Target({ElementType.METHOD, ElementType.TYPE})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        public @interface MyAnnotation {
            String[] value();
            String comment() default "hello";
        }
        
        //使用自定义的注解 MyAnnotation,并给value值"John"
        @MyAnnotation("John")
        public class MyTest {
            public static void test(){
                //透过反射取得某个类上的某个注解
                MyAnnotation config = MyTest.class.getAnnotation(MyAnnotation.class);
                System.out.println("value: " + config.value() + ", comment: " + config.comment());
            }
        }
        
        public class MainTest{
            public static void main(String[] args) {
                MyTest.test();  //输出 value: John, comment: hello 
            }
        }
      • 使用 @Repeatable 元注解

        public class FindFiles{
        
            //此注解接住 FileType 注解,并把它存起来
            @Target(ElementType.METHOD)
            @Retention(RetentionPolicy.RUNTIME)
            public @interface FileTypes {
                FileType[] value();
            }
        
            //自定义的注解,可以想像成是一个自定义的对象,裡面有很多成员变量
            //使用 @Repeatable 让这个注解可以被重複使用
            //并且 @Repeatable 还指定这个 FileType 注解要放到 FileTypes 注解裡
            @Target(ElementType.METHOD)
            @Retention(RetentionPolicy.RUNTIME)
            @Repeatable(FileTypes.class)
            public @interface FileType {
                String value();
                String comment();
            }
        
            @FileType(value=".java", comment="java")
            @FileType(value=".html", comment="html")
            @FileType(value=".css", comment="css")
            public void work() throws Exception {
                //透过反射取得类,并取得work方法,然后再work方法上的FileType注解们
                FileType[] fileTypes = this.getClass().getMethod("work").getAnnotationsByType(FileType.class);
                for (FileType fileType : fileTypes) {
                    System.out.println("value: " + fileType.value() + ", comment: " + fileType.comment());
                }
            }
        
            public static void main(String[] args) throws Exception {
                new FindFiles().work();
            }
        }
        //输出
        value: .java, comment: java
        value: .html, comment: html
        value: .css, comment: css


猜你喜欢

转载自blog.csdn.net/weixin_40341116/article/details/80655894
今日推荐