进阶13: 注解、java内置的需要掌握的注解、元注解、反射注解、反射方法上的注解、注解在开发中的作用

注解

  1. 什么是注解?

    • 注解,或者叫注释类型,英文单词:Annotation

    • 注解Annotation是一种引用数据类型,编译之后也是生成xxx.class文件

    • 自定义注解的语法格式:

      ​ [修饰符列表] @interface 注解类型名{

      ​ }

      package annotation;
      
      /*
          自定义注解:MyAnnotation
       */
      public @interface MyAnnotation {
      }
      
  2. 注解怎么使用,用在什么地方?

    • 第一:注解使用时的语法格式是: @注解类型名

    • 第二:注解可以出现在类上、属性上、方法上、变量上等…

      注解还可以出现在注解类型上。

      package annotation;
      
      //默认情况下,注解可以出现在任意位置
      @MyAnnotation
      public class AnnotationTest01 {
          @MyAnnotation
          private int no;
      
          @MyAnnotation
          public AnnotationTest01(){
      
          }
      
          @MyAnnotation
          public static void m1(){
              @MyAnnotation
              int i = 100;
          }
      
          @MyAnnotation
          public void m2(@MyAnnotation String name,@MyAnnotation int k){
      
          }
      }
      
      @MyAnnotation
      interface MyInterface{
      
      }
      
      @MyAnnotation
      enum Season{
          SPRING,SUMMER,AUTUMN,WINTER
      }
      

      注解修饰注解

      package annotation;
      
      //注解修饰注解
      @MyAnnotation
      public @interface OtherAnnotation {
      }
      
  3. JDK中内置了哪些注解?

    • 掌握:

      Deprecated 用@Depercated注解的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择

      package annotation;
      /*
          @Deprecated表示:已过时
       */
      public class AnnotationTest03 {
          @Deprecated
          public void doSome(){
              System.out.println("do something");
          }
      
          //Deprecated 这个注解标注的元素已过时
          //这个注解主要是向其他程序员传递一个信息:让他们知道这个过时了,有更好的解决方案存在。
          @Deprecated
          public static void doOther(){
              System.out.println("do other---");
          }
      }
      
      class T{
          public static void main(String[] args) {
              AnnotationTest03 at = new AnnotationTest03();
              at.doSome();
      
              AnnotationTest03.doOther();
          }
      }
      
    • 掌握:

      Override 表示一个方法重写父类中的另一个方法

      package annotation;
      
      /*
          关于JDK lang包下的Override注解
          源代码:
          public @interface Override{
      
          }
      
          标识性注解,给编译器做参考的。
          编译器看到方法上有这个注解的时候,编译器会自动检查该方法是否重写了父类的方法,如果没有从重写,就报错
          这个注解只是在编译阶段起作用,和运行期无关
      
          注意:
              1、@Override这个注解只能注解方法。
      
              2、@Override这个注解是给编译器参考的,和运行阶段没有关系。
      
              3、凡是java中的方法带有这个注解的,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器报错
      
      
       */
      
      //@Override //报错
      public class AnnotationTest02 {
          @Override
          public String toString() {
              return super.toString();
          }
          //@Override //报错
          public static void main(String[] args) {
      
          }
      } 
      
    • 不用掌握

      SuppressWarnings 指示应该在注释元素(以及包含在该注解元素中的所有程序元素)中取消显示指定的编译器警告。

  4. 元注解

    • 什么是元注解?

      用来标注“注解类型”的“注解”,称为“元注解”

    • 常见的注解类型有哪些?

      Target

      Retention

    • 关于Target注解:

      这是一个元注解,用来标注“注解类型”的“注解”

      这个Target注解用来标注“被标注的注解”可以出现在哪些位置上。

      @Target(ElementType.METHOD):表示“被标识的注解”只能出现在方法上

      @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
      //表示该注解可以出现在:构造方法上、字段上、局部变量上、方法上···类上等等
      
    • 关于Retention注解:

      这是一个元注解,用来标注“注解类型”的“注解”

      这个Retention注解用来标注“被标注的注解”最终保存在哪里。

      @Retention(RetentionPolicy.SOURCE):表示该注解只能被保留在java文件中。

      @Retention(RetentionPolicy.CLASS):表示该注解只能被保存在class文件中。

      @Retention(RetentionPolicy.RUNTIME):表示该注解只能被保存在class文件中,并且可以被反射机制所读取。

  5. 自定义元注解,当元注解中有属性时

    注解类型

    package annotation2;
    
    public @interface MyAnnotation {
        /**
         * name属性
         * 我们通常在注解当中可以定义属性,以下这个是MyAnnotation的name属性。
         * 看着像一个方法,但实际上我们称之为属性name
         * @return
         */
        String name();
    
        /**
         * 颜色属性
         * @return
         */
        String color();
    
        /**
         * 年龄属性
         * @return
         */
        int age() default 25;   //属性指定默认值
    }
    

    测试

    package annotation2;
    
    public class MyAnnotationTest {
    
        //报错原因:如果一个注解当中有属性,那么必须给属性赋值(除非该属性使用default指定了默认值)
    /*    @MyAnnotation
        public void doSOme(){}*/
    
        //@MyAnnotation(属性名 =属性值,属性名 =属性值,属性名 =属性值)
        //指定name属性的值就好了
        @MyAnnotation(name ="zhangsan",color = "red")
        public void doSome(){
    
        }
    
    }
    
  6. 如果一个注解的属性名是:value,并且该注解类型中只有这一个属性时在使用的时候,该属性名可以省略

    注解类型

    package annotation3;
    
    public @interface MyAnnotation {
        //指定一个value属性
        String value();
    
        //String email();
    }
    

    测试

    package annotation3;
    
    /*
        如果一个注解的属性名是:value,并且该注解类型中只有这一个属性时在使用的时候,该属性名可以省略
     */
    public class MyAnnotationTest {
        @MyAnnotation(value = "hehe")
        public void doSome(){
    
        }
    
        @MyAnnotation("haha")
        public void doOther(){
    
        }
    }
    
  7. 除value外,其他的都不能省略

    注解类型

    package annotation3;
    
    
    public @interface OtherAnnotation {
        String name();
    }
    

    测试

    package annotation3;
    
    //@OtherAnnotation("test")  //报错:因为属性民是name,不能省略
    public class OtherAnnotationTest {
    
        //正确的
        @OtherAnnotation(name = "test")
        public void doSome(){
    
        }
    }
    
  8. 注解当中的属性可以是哪种类型?

    枚举类型

    package annotation4;
    
    public enum Season {
        SPRING,SUMMER,AUTUMN,WINTER
    }
    

    可以是:

    package annotation4;
    
    public @interface MyAnnotation {
        /*
            注解当中的属性可以是哪种类型?
                属性的类型可以是:
                    byte、short、int、long、float、double、char、String、Class、枚举类型
                    以上以及每一种类型的数组形式
    
         */
    
        int value1();
    
        String value2();
    
        int[] value3();
    
        String[] value4();
    
        Season value5();
    
        Season[] value6();
    
        Class parameterType();
    
        Class[] parameterTypes();
    }
    
  9. 注解中的属性为数组时,如果只写一个参数,则大括号可以省略,属性有枚举类型时怎么用

    注解类型

    package annotation4;
    
    public @interface OtherAnnotation {
        //年龄属性
        int age();
    
        //邮箱地址属性,支持多个
        String[] email();
    
        //季节数组
        Season[] seasonArray();
    }
    

    测试

    package annotation4;
    
    public class OtherAnnotationTest {
    
        @OtherAnnotation(age=25,email = {"zhangsan@123.com","zhangsan@sohu.com"},seasonArray = {Season.SPRING,Season.AUTUMN})
        public void doSome(){
    
        }
    
        //如果数组中只有1个元素:大括号可以省略
        @OtherAnnotation(age=25,email = "zhangsan@123.com",seasonArray = Season.WINTER)
        public void doOther(){
    
        }
    
    
    }
    
  10. Rerention的源代码

    public @interface Retention{
    	//属性
    	RetentionPolicy value();
    }
    
    //RetentionPolicy源代码
    public enum RetentionPolicy{
        SOURCE,
        CLASS,
        RUNTIME
    }
    
    //@Retention(value = RententionPolicy.RUNTIME)	value可以省略:
    @Retention(RententionPolicy.RUNTIME)
    public @interface MyAnnotation{
        
    }
    
  11. 反射注解

    注解类型

    package annotation5;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    //只允许该注解标注类、方法
    @Target({ElementType.TYPE,ElementType.METHOD})
    //希望这个注解可以被反射
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
        String value() default "大山西";
    }
    

    测试类

    package annotation5;
    
    @MyAnnotation
    public class MyAnnotationTest {
    
        //@MyAnnotation
        int i;
    
        //@MyAnnotation
        public MyAnnotationTest(){
    
        }
    
        @MyAnnotation
        public void doSome(){
    
        }
    }
    

    反射注解

    package annotation5;
    //反射注解
    public class ReflectAnnotationTest {
        public static void main(String[] args) throws Exception{
            //获取这个类
            Class c =Class.forName("annotation5.MyAnnotationTest");
            //判断类上面是否有@MyAnnotation
            //System.out.println(c.isAnnotationPresent(MyAnnotation.class));
            if(c.isAnnotationPresent(MyAnnotation.class)){
                //获取该注解对象
                MyAnnotation myAnnotation =(MyAnnotation)c.getAnnotation(MyAnnotation.class);
                //System.out.println("类上面的注解对象"+myAnnotation);//@annotation5.MyAnnotation()
                //获取注释对象的属性怎么办?(和掉调接口没区别)
                String value = myAnnotation.value();
                System.out.println(value);  //大山西   //如果类上的注解中有参数,则获取其中的值,如果没有,则获取的是默认值
    
            }
    
            //判断String类上面是否存在这个注解
            Class stringClass = Class.forName("java.lang.String");
            System.out.println(stringClass.isAnnotationPresent(MyAnnotation.class));
        }
    }
    
  12. 反射方法上的注解

    注解类型

    package annotation6;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyAnnotation {
        //username属性
        String username();
        //password属性
        String password();
    }
    

    反射

    package annotation6;
    
    import java.lang.reflect.Method;
    //反射方法上的注解
    public class MyAnnotationTest {
    
        @MyAnnotation(username = "admin",password = "123")
        public void doSOme(){
        }
    
        public static void main(String[] args) throws Exception{
            //获取MyAnnotationTest的doSome()方法上面的注解信息
            Class c = Class.forName("annotation6.MyAnnotationTest");
            //获取doSome方法
            Method doSomeMethod = c.getDeclaredMethod("doSOme");
            //判断该方法上是否有这个注解
            if(doSomeMethod.isAnnotationPresent(MyAnnotation.class)){
                MyAnnotation myAnnotation =(MyAnnotation)doSomeMethod.getAnnotation(MyAnnotation.class);
                System.out.println(myAnnotation.username());
                System.out.println(myAnnotation.password());
            }
    
        }
    }
    
  13. 注解在开发中有什么用呢?

    需求:

    ​ 假设有这样一个注解:@Id。只能出现在类上面,要求这个类中必须有一个int类型的id属性,如果没有这个属性就报异常,如果有这个属性则正常运行

    注解类型

    package annotation7;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    //只能出现在类上面
    @Target(ElementType.TYPE)
    //该注解可以被反射机制读取
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MustHaveIdPropertyAnnotation {
    
    }
    
    //这个注解Id用来标注类,被标注的类中必须有一个int类型的id属性,没有就报异常。
    

    User类

    package annotation7;
    
    @MustHaveIdPropertyAnnotation
    public class User {
        int id;
        String name;
        String password;
    }
    

    异常类

    package annotation7;
    
    /*
        自定义异常
     */
    public class WithoutIdPropertyException extends RuntimeException  {
        public WithoutIdPropertyException(){
    
        }
        public WithoutIdPropertyException(String s){
            super(s);
        }
    }
    

    测试类

    package annotation7;
    
    
    import java.lang.reflect.Field;
    
    public class Test {
        public static void main(String[] args) throws Exception{
            //获取类
            Class userClass = Class.forName("annotation7.User");
            //判断类上面是否有Id注解
            if(userClass.isAnnotationPresent(MustHaveIdPropertyAnnotation.class)){
                //如果存在Id注解,则要求类中必须存在int类型的id属性;如果没有int类型的id属性则报异常
                //获取类的属性
                Field[] fields = userClass.getDeclaredFields();
                boolean isOk = false;   //给一个默认标记
                for(Field field :fields){
                    if("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
                        //能执行到这里表示这个带有@Id注解类中有int类型的id属性
                        isOk = true;    //合法
                        break;      //结束循环
                    }
                }
                //循环结束后判断该类是否符合需求
                if(!isOk){
                    throw new WithoutIdPropertyException("此类中没有int类型的id属性,不符合需求");
                }
    
            }
        }
    }
    
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页