注解
-
什么是注解?
-
注解,或者叫注释类型,英文单词:Annotation
-
注解Annotation是一种引用数据类型,编译之后也是生成xxx.class文件
-
自定义注解的语法格式:
[修饰符列表] @interface 注解类型名{
}
package annotation; /* 自定义注解:MyAnnotation */ public @interface MyAnnotation { }
-
-
注解怎么使用,用在什么地方?
-
第一:注解使用时的语法格式是: @注解类型名
-
第二:注解可以出现在类上、属性上、方法上、变量上等…
注解还可以出现在注解类型上。
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 { }
-
-
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 指示应该在注释元素(以及包含在该注解元素中的所有程序元素)中取消显示指定的编译器警告。
-
-
元注解
-
什么是元注解?
用来标注“注解类型”的“注解”,称为“元注解”
-
常见的注解类型有哪些?
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文件中,并且可以被反射机制所读取。
-
-
自定义元注解,当元注解中有属性时
注解类型
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(){ } }
-
如果一个注解的属性名是: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(){ } }
-
除value外,其他的都不能省略
注解类型
package annotation3; public @interface OtherAnnotation { String name(); }
测试
package annotation3; //@OtherAnnotation("test") //报错:因为属性民是name,不能省略 public class OtherAnnotationTest { //正确的 @OtherAnnotation(name = "test") public void doSome(){ } }
-
注解当中的属性可以是哪种类型?
枚举类型
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(); }
-
注解中的属性为数组时,如果只写一个参数,则大括号可以省略,属性有枚举类型时怎么用
注解类型
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(){ } }
-
Rerention的源代码
public @interface Retention{ //属性 RetentionPolicy value(); } //RetentionPolicy源代码 public enum RetentionPolicy{ SOURCE, CLASS, RUNTIME } //@Retention(value = RententionPolicy.RUNTIME) value可以省略: @Retention(RententionPolicy.RUNTIME) public @interface MyAnnotation{ }
-
反射注解
注解类型
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)); } }
-
反射方法上的注解
注解类型
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()); } } }
-
注解在开发中有什么用呢?
需求:
假设有这样一个注解:@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属性,不符合需求"); } } } }