> 文章列表 > 【java进阶13: 注解】java内置的需要掌握的注解、元注解、反射注解、反射方法上的注解、注解在开发中的作用

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

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

注解

  1. 什么是注解?

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

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

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

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

      ​ }

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

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

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

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

      package annotation;//默认情况下,注解可以出现在任意位置
      @MyAnnotation
      public class AnnotationTest01 {@MyAnnotationprivate int no;@MyAnnotationpublic AnnotationTest01(){}@MyAnnotationpublic static void m1(){@MyAnnotationint i = 100;}@MyAnnotationpublic 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 {@Deprecatedpublic void doSome(){System.out.println("do something");}//Deprecated 这个注解标注的元素已过时//这个注解主要是向其他程序员传递一个信息:让他们知道这个过时了,有更好的解决方案存在。@Deprecatedpublic 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 {@Overridepublic 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指定了默认值)
    /*    @MyAnnotationpublic 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 {//@MyAnnotationint i;//@MyAnnotationpublic MyAnnotationTest(){}@MyAnnotationpublic 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属性,不符合需求");}}}
    }