1、Annotation概述
Annotation其实就是代码里的特殊标记,它用于代替配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,我们可以通过注解告诉类如何运行
2.三个基本的Annotation
(1)@Override:限定重写父类的方法,该注解只能用于方法 (2)@Deprecated:用于表示某个程序元素(类、方法等)已过时 (3)@SuppressWarings:抑制编译器警告 |
例:练习@Override
package com.heima.annotation; publicclass AnnotationDemo1 { @Override//限定重写父类的方法 publicboolean equals(Object obj){ returnsuper.equals(obj); } } |
如果你在复写父类的方法时,把参数给写错了,如下
package com.heima.annotation; publicclass AnnotationDemo1 { @Override//限定重写父类的方法 publicboolean equals(String obj){ returnsuper.equals(obj); } } |
此时编译器就会报错,如果没有注解的话,它就不会报错。
例:练习@SuppressWarnings
publicvoid test1(){ List list=new ArrayList(); list.add("黑马_1"); list.add("黑马_2"); list.add("黑马_3"); } |
如果上面不加注解的话会出现很多警告,如图
当我们在方法上加上注解时
@SuppressWarnings("unchecked") publicvoid test1(){ List list=new ArrayList(); list.add("黑马_1"); list.add("黑马_2"); list.add("黑马_3"); } |
此注解是给编译器看的,上面的注解告诉编译器压制警告。此时那些注解就不存在了,如图:
例:练习@Deprecated
@Deprecated publicvoid System.out.println("aaaa"); } |
此注解是给编译器看的,上面的注解就是告诉编译器,当看到这个注解时,就让方法过时。
2、我们学习注解时应该掌握的知识
(1)编写注解 (2)解析注解,并根据注解信息去运行程序。 |
2.1、自定义Annotation
(1)自定义注解的目标:原来写在配置文件中的信息,可以通过注解描述
(2)定义Annotation使用@interface关键字
(3)配置文件的信息,在注解中采用属性描述
例如:
String name();//定义一个属性 String name() default “aaa”;//带默认值的方式 |
例:创建一个自定义的注解
package com.heima.annotation; //创建一个自定义注解 public@interfaceMyAnnotation1 { String name(); int age(); } |
使用注解
@MyAnnotation1(name="黑马_1",age=23) publicvoid test3(){
} |
我们知道以前name和age属性都在xml中配置,此时用注解直接在程序中就可以配置了。
注解支持的属性的数据类型如下:
(1)String类型 (2)8大基本数据类型 (3)Class类型 (4)枚举类型 (5)注解类型 (6)以上类型的一维数组 |
注解的属性只支持以上的数据类型,如果配其他的类型会出现错误。
上图中出现了错误(无效的属性),所以注解不支持集合类型的属性,就是说除了上面所列举的类型外,其他的类型都不能作为注解的属性。
注解中有一个特殊属性value:如果注解中有一个名称的属性,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxxx”)
特殊属性value[];例如@SuppressWanings(“unchecked”)就是String[]value();但是如果一个注解中有两个以上的属性时,就不能省略了如:
@MyAnnotation1(value="黑马_1",age=23) publicvoid test3(){
} |
3、元注解
元Annotation指修饰Annotation的Annotation,JDK中定义了如下元Annotation
3.1、@Retention
只能用于修饰一个Annotation定义,用于指定该Annotation可以保留的域,@Retention包含一个RetentionPolicy类型的成员变量,通过这个变量指定域
(1)RetentionPolicy.CLASS:编译器将把注解记录在class文件中,当运行Java程序时,JVM不会保留注解,这是默认值 (2)RetentionPolicy.RUNTIME:编译器将把注解记录在class文件中,当运行Java程序时,JVM会保留注解,程序可以通过反射获取该注解 (3)RetentionPolicy.SOURCE:编译器直接丢弃这种策略的注解 |
我们知道一个Java类具有三种状态,分别如下:
(1)Java源代码状态(RetentionPolicy.SOURCE) (2)class状态:Java源代码编程成.class(RetentionPolicy.CLASS) (3)运行状态:JVM把class文件装载到内存中才能运行(RetentionPolicy.RUNTIME) |
例:RetentionPolicy.SOURCE
//创建一个自定义注解 @Retention(RetentionPolicy.SOURCE) public@interfaceMyAnnotation1 { String name(); int age(); } |
如果我们把注解设置成RetentionPolicy.SOURCE,这个注解只能在源代码时有效,当编译成Class文件时,此时注解就不在其作用了
例:RetentionPolicy. CLASS
//创建一个自定义注解 @Retention(RetentionPolicy.CLASS) public@interfaceMyAnnotation1 { String name(); int age(); } |
如果我们把注解设置成RetentionPolicy. CLASS,这个注解在源代码和编译后的class文件中有效,当把class放到内存中运行时就不起作用了。
例:RetentionPolicy. CLASS
//创建一个自定义注解 @Retention(RetentionPolicy.RUNTIME) public@interfaceMyAnnotation1 { String name(); int age(); }
|
如果我们把注解设置成RetentionPolicy. RUNTIME,这个注解在源代码和编译后的class文件中有效,当把class放到内存中运行也作用了。
通过上面的三个事例说明,当我们自定义Annotation时,要考虑我们在什么时候用到这个注解,如果我们需要在运行时用,而我们并没有设置它的元Annotation,则默认为RetentionPolicy. CLASS,此时,我们在注解中设置的数据在运行时就无法得到了。
3.2、@Target(用于规定注解作用在类的那些地方)
指定注解用于修饰类的哪个成员,@Target包含了一个名为value,类型为ElementType的成员变量
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.CONSTRUCTOR,ElementType.LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) public@interfaceMyAnnotation1 { String name(); int age(); } |
上例表明我定义的注解可以作用在类型上、属性上,方法上,构造方法上,局部变量上,如果我们不定义,则默认可以作用在类的任何一个地方。
3.3、@Documented(用的不多)
用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档
3.4、@Inherited
被它修饰的Annotation将具有继承性,如果某个类用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
4、解析注解
范例一:利用注解链接Mysql
自定义一个注解DbInfo
package com.heima.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; //把自定义的注解设置成RetentionPolicy.RUNTIME @Retention(RetentionPolicy.RUNTIME) public@interfaceDbInfo { String driver();//设置一个driver属性 String url();//设置一个url属性 String user();//设置一个user属性 String password();//设置一个password属性
}
|
注意在自定义注解时,一定要考虑这个注解用在哪,否则会出现错误,这个注解用到运行时,所以要修改它的元注解。
package com.heima.annotation; import java.lang.reflect.Method; import java.sql.Connection; publicclass AnnotationDemo2 { privatestatic Stringdriver; privatestatic Stringurl; privatestatic Stringuser; privatestatic Stringpassword; static{//只用一次,所以写在静态代码块中 try { //利用反射解析出getConnection方法 Method m=AnnotationDemo2.class.getMethod("getConnection",null); //获取此方法上的注解 DbInfo info=m.getAnnotation(DbInfo.class);
driver=info.driver();//获取注解上driver的属性 url=info.url();//获取注解上url的属性 user=info.user();//获取注解上user的属性 password=info.password();//获取注解上password的属性 } catch (Exception e) { thrownew RuntimeException(e); }
} @DbInfo(driver="com.mySql.jdbc.Driver",url="jdbc:mysql://localhost:3306/student",user="root",password="mysql") publicstatic Connection getConnection(){ System.out.println(driver); System.out.println(url); System.out.println(user); System.out.println(password); returnnull; } publicstaticvoid main(String[] args) { getConnection();//调用getConnection方法 } } |
运行结果如下:com.mySql.jdbc.Driver
jdbc:mysql://localhost:3306/student
root
mysql