【java进阶13: 注解】java内置的需要掌握的注解、元注解、反射注解、反射方法上的注解、注解在开发中的作用
注解
-
什么是注解?
-
注解,或者叫注释类型,英文单词:Annotation
-
注解Annotation是一种引用数据类型,编译之后也是生成xxx.class文件
-
自定义注解的语法格式:
[修饰符列表] @interface 注解类型名{
}
package annotation;/*自定义注解:MyAnnotation*/ public @interface MyAnnotation { }
-
-
注解怎么使用,用在什么地方?
-
第一:注解使用时的语法格式是: @注解类型名
-
第二:注解可以出现在类上、属性上、方法上、变量上等…
注解还可以出现在注解类型上。
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 { }
-
-
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 指示应该在注释元素(以及包含在该注解元素中的所有程序元素)中取消显示指定的编译器警告。
-
-
元注解
-
什么是元注解?
用来标注“注解类型”的“注解”,称为“元注解”
-
常见的注解类型有哪些?
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指定了默认值) /* @MyAnnotationpublic 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 {//@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));} }
-
反射方法上的注解
注解类型
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属性,不符合需求");}}} }