> 文档中心 > JavaSE 最后一篇 | 注解Annotation

JavaSE 最后一篇 | 注解Annotation


✅作者简介:一位材料转码农的选手,希望一起努力,一起进步!

📃个人主页:@每天都要敲代码的个人主页

🔥系列专栏:JavaSE从入门到精通

💬推荐一款模拟面试、刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习

目录

一:注解

1. 注解的定义和使用

2. JDK内置的注解

2.1 Override注解

2.2 Deprecated注解

2.3 元注解Target和Retention

2.4 在注解中定义属性

2.5 属性是value时可以省略

2.6 注解的属性是一个数组

3. 注解的作用

3.1 反射注解

3.2 方法上的注解(通过反射获取注解对象属性的值)

3.3 注解在实际开发中的作用

结束语


一:注解

1. 注解的定义和使用

(1)注解,或者叫做注释类型,英文单词是:Annotation

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

(3)怎么自定义注解呢?语法格式?           

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

(4)注解怎么使用,用在什么地方?

        第一:注解使用时的语法格式是:@注解类型名        
        第二:注解可以出现在类上、属性上、方法上、变量上等....
        注解还可以出现在注解类型上;默认注解可以出现在任意位置上!

自定义一个注解

ackage com.bjpowernode.java.annotation;// 自定义注解:MyAnnotationpublic @interface MyAnnotation {}

注解的使用

package com.bjpowernode.java.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,SUMMARY,AUTUMN,WINTER}

在定义一个注解OtherAnnotation,MyAnnotation注解也可以出现在注解OtherAnnotation上

package com.bjpowernode.java.annotation;@MyAnnotation // 注解修饰注解public @interface OtherAnnotation {}

2. JDK内置的注解

java.lang包下的注释类型:
   (1)Deprecated: 用 @Deprecated 注释的程序元素,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。 (掌握)
   (2)Override: 表示一个方法声明打算重写超类中的另一个方法声明。(掌握) 
   (3)SuppressWarnings 指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。(了解)

2.1 Override注解

关于JDK java.lang包下的Override注解
(1)源代码:

    public @interface Override {    }

(2)@Override这个注解只能注解方法
(3)@Override这个注解是给编译器参考的,和运行阶段没有关系
(4)凡是java中的方法带有这个注解的,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器报错
总结:标识性注解,给编译器做参考的;编译器看到方法上有这个注解的时候,编译器会自动检查该方法是否重写了父类的方法;如果没有重写,报错;这个注解只是在编译阶段起作用,和运行期无关!

package com.bjpowernode.java.annotation;public class AnnotationTest02 {    // 我们使用快捷键重写toString方法,默认会有@Override注解    @Override // 给编译器看的,表示已经重写了方法    public String toString() { return "AnnotationTest02{}";    }}

 2.2 Deprecated注解

(1)Deprecated表示这个注解标注的元素已过时;这个注解主要是向其它程序员传达一个信息,告知已过时,有更好的解决方案存在。

(2)原码分析:

 // 表示该注解被保存在class文件中(运行时会有提示),并且可以被反射机制所读取。@Retention(RetentionPolicy.RUNTIME)// 出现的位置@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated {}
package com.bjpowernode.java.annotation;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;public class AnnotationTest03 {    public static void main(String[] args) { MethodTest m = new MethodTest(); m.doSome(); // 有横线,表示已过时 MethodTest.doOther();// 有横线,表示已过时    }}class MethodTest{    @Deprecated // 表示这个方法已过时    public void doSome(){ System.out.println("do something!");    }    @Deprecated // 表示这个方法已过时    public static void doOther(){ System.out.println("do otherthing");    }}

 2.3 元注解Target和Retention

(1)元注解:用来标注“注解类型”的“注解”,称为元注解。

(2)为什么Override注解只能出现在方法上,那是因为元注解的修饰限制

@Target(ElementType.METHOD) // Target是一个元注解,表示只能出现在方法上@Retention(RetentionPolicy.SOURCE) // Retention是一个元注解,表示“被标注的注解”最终保存在哪里public @interface Override { }

(3)常见的元注解有哪些? Target和Retention
(4)关于Target注解:
            这个Target注解用来标注“被标注的注解”可以出现在哪些位置上

            @Target(ElementType.METHOD):表示“被标注的注解”只能出现在方法上。
            @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
                表示该注解可以出现在:
                    构造方法上 字段上 局部变量上 方法上 ....  类上...
(5)关于Retention注解:
            这个Retention注解用来标注“被标注的注解”最终保存在哪里

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

2.4 在注解中定义属性

自定义注解

package com.bjpowernode.java.Annotation2;// 在注解中定义属性public @interface MyAnnotation {    // 在注解中定义属性    // 注解中的属性需要加上小括号 ()    String name(); // MyAnnotation的name属性,不是方法!    String color(); // 颜色属性    int age() default 25; // 属性指定默认值}

(1)如果一个注解当中有属性,那么使用时必须给属性赋值,不然会报错!或者给该属性使用default指定了默认值 !

(2)格式是: @注解名(属性名=属性值,属性名=属性值....)

package com.bjpowernode.java.Annotation2;public class MyAnnotationTest {    // @MyAnnotation() 这里会报错,因为注解里有name()属性,但是没赋值    // 报错的原因:如果一个注解当中有属性,那么必须给属性赋值,或者给该属性使用default指定了默认值    // @MyAnnotation(属性名=属性值,属性名=属性值....)    @MyAnnotation(name="zhangsan",color = "red") // age属性指定了默认值,这里就可以不用写上了    public void doSome(){    }}

2.5 属性是value时可以省略

如果一个注解的属性的名字是value,并且只有一个属性的话,在使用的时候,该属性名可以省略。

 自定义属性

package com.bjpowernode.java.annotation3;public @interface MyAnnotation {    String value(); // 只定一个value属性}
package com.bjpowernode.java.annotation3;public class MyAnnotationTest {    @MyAnnotation(value = "hehe") // 正常使用    public void doSome(){ System.out.println("doSome...");    }    @MyAnnotation("haha") // value省略也是可以的    public void doOther(){ System.out.println("doOther...");    }}

2.6 注解的属性是一个数组

注解当中的属性可以是哪一种类型?
属性的类型可以是:byte short int long float double boolean char String Class 枚举类型以及以上每一种的数组形式

定义一个枚举类型

package com.bjpowernode.java.annotation4;public enum Season {    SPRING,SUMMER,AUTUMN,WINTER}

 属性的类型

package com.bjpowernode.java.annotation4;public @interface MyAnnotation {     int value1();    int[] value3();    String value2();    String[] value4(); // Strin类型及数组    Season value5();    Season[] value6(); // 枚举类型及数组    Class parameterType();    Class[] parameterTypes(); // Class类型及数组}

当属性是数组时写法和用法

package com.bjpowernode.java.annotation4;public @interface OtherAnnotation {    int age(); // 年龄属性    String[] emails(); // 邮箱属性,支持多个    Season[] seasonArray();}
package com.bjpowernode.java.annotation4;public class OtherAnnotationTest {    // 数组是大括号    @OtherAnnotation(age = 25, emails = {"zhangsan@123.com", "zhangsan@sohu.com"},seasonArray = {Season.AUTUMN,Season.SPRING})    public void doSome(){    }    // 如果数组中只有1个元素:大括号可以省略。    @OtherAnnotation(age = 25, emails = "zhangsan@123.com",seasonArray = Season.AUTUMN)    public void doOther(){    }}

3. 注解的作用

3.1 反射注解

定义注解

package com.bjpowernode.java.annotation5;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;// 只允许该注解标注类、方法(ElementType是一个枚举)@Target(value = {ElementType.TYPE,ElementType.METHOD}) // value可以被省略// 希望这个注解可以被反射@Retention(value = RetentionPolicy.RUNTIME) // value可以被省略public @interface MyAnnotation {    String value() default "安徽省";}

使用注解的类 

package com.bjpowernode.java.annotation5;@MyAnnotationpublic class MyAnnotationTest {    @MyAnnotation    public void doSome(){ int i;    }}

反射类上注解的属性

package com.bjpowernode.java.annotation5;// 反射注解public class ReflectAnnotationTest {    public static void main(String[] args) throws Exception { // 获取类 Class c = Class.forName("com.bjpowernode.java.annotation5.MyAnnotationTest"); // 判断类上面是否有@MyAnnotation注解 boolean b = c.isAnnotationPresent(MyAnnotation.class); // System.out.println(b); // true // 如果存在,获取注解 if(b){     // 获取该注解对象     // 参数是Class,返回类型是Annotation,需要强制类型转换     MyAnnotation myAnnotation = (MyAnnotation) c.getAnnotation(MyAnnotation.class);     // System.out.println(myAnnotation); // @com.bjpowernode.java.annotation5.MyAnnotation(value=安徽省)     // 获取注解对象的属性     String value = myAnnotation.value();     System.out.println(value); // 安徽省 }    }}

3.2 方法上的注解(通过反射获取注解对象属性的值)

package com.bjpowernode.java.annotation6;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD) // 只能出现在方法上@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotation {    String username(); // 用户属性    String password(); // 密码属性}
package com.bjpowernode.java.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("com.bjpowernode.java.annotation6.MyAnnotationTest"); // 获取doSome()方法 Method doSomeMethod = c.getDeclaredMethod("doSome"); // System.out.println(doSomeMethod); // 判断方法上有没有注解 if(doSomeMethod.isAnnotationPresent(MyAnnotation.class)){     MyAnnotation myAnnotation = doSomeMethod.getAnnotation(MyAnnotation.class);     System.out.println(myAnnotation.username()); // admin     System.out.println(myAnnotation.password()); // 123 }    }}

3.3 注解在实际开发中的作用

需求:假设有这样一个注解,叫做:@Id;这个注解只能出现在类上面,当这个类上有这个注解的时候,要求这个类中必须有一个int类型的id属性。如果没有这个属性就报异常。如果有这个属性则正常执行!

自定义注解

package com.bjpowernode.java.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 Id {}

User类

package com.bjpowernode.java.annotation7;@Idpublic class User {    // 这个类上必须有int的id属性    int id;    String name;    String password;}

异常

package com.bjpowernode.java.annotation7;// 自定义异常public class HasNotIdException extends RuntimeException{    public HasNotIdException(){}    public HasNotIdException(String s){ super(s);    }}

测试

package com.bjpowernode.java.annotation7;import java.lang.reflect.Field;public class Test {    public static void main(String[] args) throws Exception{ // 获取类 Class userClass = Class.forName("com.bjpowernode.java.annotation7.User"); // 判断类上是否存在Id注解 if(userClass.isAnnotationPresent(Id.class)){     // 有Id注解,要求类中必须存在int类型的id属性     // 获取类的属性     Field[] fields = userClass.getDeclaredFields();     boolean isOk = false; // 给一个默认的标记     for(Field field :fields){  if("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){      isOk = true;      break;  }     }     // 没有int类型的id属性     if(!isOk){  // 抛出异常  throw new HasNotIdException("被@MustHasIdPropertyAnnotation注解标注的类中必须要有一个int类型的id属性!");     } }    }}

结束语

今天的分享就到这里啦!快快通过下方链接注册加入刷题大军吧!

各种大厂面试真题在等你哦!
💬刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习