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属性!"); } } }}
结束语
今天的分享就到这里啦!快快通过下方链接注册加入刷题大军吧!
各种大厂面试真题在等你哦!
💬刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习