一、注解
- 注解(Annotation)是一种引用数据类型,编译之后也是生成xxx.class文件。
- 自定义注解的语法格式:
[修饰符列表] @interface 注解类型名{ }
- 注解的使用:
- 注解使用时的语法格式:@注解类型名
- 注解可以出现在类上、属性上、方法上、变量上等…注解还可以出现在注解类型上。
- JDK内置的注解:
- java.lang包下的注解类型:
Deprecated
:用@Deprecated 注释的程序元素表示该元素已过时,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。Override
:表示一个方法声明打算重写超类中的另一个方法声明。SuppressWarnings
:指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。
- java.lang包下的注解类型:
- 元注解:用来标注"注解类型"的"注解",称为"元注解"。
- 常见的元注解:
Target
:用来标注"被标注的注解"可以出现在哪些位置上。- @Target(ElementType.METHOD): 表示"被标注的注解"只能出现在方法上
- @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE}): 表示"被标注的注解"可以出现在构造方法上,字段上,局部变量上,方法上,包上,模块上,参数上,类上。
Retention
:用来标注"被标注的注解"最终保存在哪里。- @Retention(RetentionPolicy.SOURCE): 表示"被标注的注解"只被保留在java源文件中。
- @Retention(RetentionPolicy.CLASS): 表示"被标注的注解"被保存在class文件中。
- @Retention(RetentionPolicy.RUNTIME): 表示"被标注的注解"被保存在class文件中,并且可以被反射机制所读取。
- 常见的元注解:
- 注解当中可以定义属性
-
如果一个注解当中有属性,那么注解在标注时必须给属性赋值。(除非该属性使用default指定了默认值)
-
如果一个注解的属性的名字是value,并且只有一个属性的话,在使用注解的时候,该属性名可以省略。
-
注解当中属性的类型可以是:
byte、short、int、long、float、double、boolean、char、String、Class、枚举类型
以及以上每一种的数组形式。 -
如果注解当中属性为数组,在使用注解时如若数组有多个元素,用大括号表示数组;如果数组中只有一个元素,大括号可以省略。
public @interface MyAnnotation { /** * 我们通常在注解当中可以定义属性,以下这个是MyAnnotation的name属性。 * 看着像1个方法,但实际上我们称之为属性name。 */ String name(); //颜色属性 String color(); //年龄属性 int age() default 25; //属性指定默认值 } public class MyAnnotationTest { //@MyAnnotation(属性名=属性值,属性名=属性值,属性名=属性值) //年龄属性有默认值可以不赋值,也可以赋指定的值 @MyAnnotation(name = "zhangsan", color = "红色") public void doSome(){ } }
-
- 通过反射机制获取Java对象中的注解(注解属性)
@Target({ElementType.METHOD,ElementType.TYPE})//该注解只能出现在类和方法上 @Retention(RetentionPolicy.RUNTIME)//该注解的保存策略为可以保存到class文件并可以被反射 public @interface MyAnnotation { //username属性 String username(); //password属性 String password(); } --------------------------------------------------------------------------------------------------- @MyAnnotation(username = "zhangsan",password = "123") public class MyAnnotationTest { @MyAnnotation(username = "lisi", password = "1234") public void doSome() { } } --------------------------------------------------------------------------------------------------- public class ReflectAnnotationTest { public static void main(String[] args) { // 1.反射MyAnnotationTest类上面的@MyAnnotation注解 try { //通过反射机制获取类class文件 Class cc = Class.forName("com.javaSE.annotation.annotation02.MyAnnotationTest"); //判断类上面是否存在@MyAnnotation注解 if (cc.isAnnotationPresent(MyAnnotation.class)) { //存在则获得注解对象 Annotation ccAnnotation = cc.getAnnotation(MyAnnotation.class); System.out.println(ccAnnotation);//@com.javaSE.annotation.annotation02.MyAnnotation(username="zhangsan", password="123") //获得注解对象中的属性 String username = ((MyAnnotation) ccAnnotation).username(); String password = ((MyAnnotation) ccAnnotation).password(); System.out.println(username);//zhangsan System.out.println(password);//123 } } catch (ClassNotFoundException e) { e.printStackTrace(); } // 2.反射MyAnnotationTest类中方法上面的@MyAnnotation注解 try { //通过反射机制获取class文件 Class cm = Class.forName("com.javaSE.annotation.annotation02.MyAnnotationTest"); //通过反射机制获取类中的方法 Method[] declaredMethods = cm.getDeclaredMethods(); for (Method method : declaredMethods) { //判断方法上是否有@MyAnnotation注解 if (method.isAnnotationPresent(MyAnnotation.class)) { //存在则获取注解对象 MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); System.out.println(annotation);//@com.javaSE.annotation.annotation02.MyAnnotation(username="lisi", password="1234") //获得该注解对象的属性 System.out.println(annotation.username());//lisi System.out.println(annotation.password());//1234 } } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
二、注解在开发中的应用
- 简单案例
假设有这样一个注解,叫做:@Id
这个注解只能出现在类上面,当这个类上有这个注解的时候,要求这个类中必须有一个int类型的id属性。如果没有这个属性就报异常。如果有这个属性则正常执行!//自定义异常:没有id属性异常 public class NoIdPropertyException extends RuntimeException { public NoIdPropertyException() { } public NoIdPropertyException(String message) { super(message); } } ----------------------------------------------------------------------------------------------------- // 这个注解用来标注类,被标注的类中必须有一个int类型的id属性,没有就报异常。 @Target(ElementType.TYPE)//该注解只能出现在类上面 @Retention(RetentionPolicy.RUNTIME)//该注解能保存在class文件中并且能被反射机制读取 public @interface IDAttributeMustBePresentAnnotation { } ----------------------------------------------------------------------------------------------------- //被该注解标注的类必须有int类型的id属性,没有则抛出异常 @IDAttributeMustBePresentAnnotation public class User { // int id; String name; boolean sex; String password; } ----------------------------------------------------------------------------------------------------- public class Test { public static void main(String[] args) { try { //通过反射机制获取类 Class c = Class.forName("com.javaSE.annotation.annotation03.User"); //判断该类上是否存在@IDAttributeMustBePresentAnnotation注解 if (c.isAnnotationPresent(IDAttributeMustBePresentAnnotation.class)) { //存在则判断该类中是否存在int类型的id属性 boolean isExists = false;//定义一个默认为不存在的判断 //获取类中的所有字段/属性 Field[] fields = c.getDeclaredFields(); for (Field field : fields) { //判断字段/属性是否存在int类型的id属性 if ("int".equals(field.getType().getSimpleName()) && "id".equals(field.getName())) { //存在则为true isExists = true; break; } } //不存在则抛出异常 if (!isExists) { throw new NoIdPropertyException("被@IDAttributeMustBePresentAnnotation标注的类必须有一个int类型的id属性"); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }