JDK的注解
注解和接口,类都一样,都是属于数据类型,
注解可以加在变量,方法,类上面
注解可以有属性,也可以没有属性:@Test(timeout=1000),@Override
注解有作用范围:源码期间,编译期间,运行期间。
-
源码期间有效:String类上的@Author,@Since,@See
- 作用:使用命令javadoc可以将当前的源码生成帮助文件,可以识别String类上的相关的注解
-
编译期间有效:@Override @Deprecated @Suppresswarning
- 作用:告诉编译器部分信息
-
运行期间有效:@Test
- 作用:当我们在当前代码上以Junit的方式运行时,Junit会运行方法上包含@Test注解的方法
-
@Override 重写方法
-
@SuppressWarnings(“unused”):抑制编译器发生警告信息,变量未使用警告
-
@SuppressWarnings(“unused”, “rawtypes”):变量未使用,未遵循泛型格式错误不报警告
-
@Deprecated:声明以下方法是过时的方法,不建议使用!
JUnit的第三方的包
- @Test(timeout=1000):1000毫秒之内若未执行完成,就会报错!
自定义注解(Annotation)
格式:
public @interface 注解名称{
public long timeout();//给注解定义了个属性
public long timeout() default -1;//给注解的属性赋予一个默认值
//public 属性类型 属性名称() default 默认值;
//支持的属性类型有:基本数据类型(4类8种),String,Class,Annotation(注解类型),枚举类型,以及以上类型的一维数组类型
public Class c() default java.util.Date.Class
}
支持的数据类型
- 基本数据类型(4类8种)
- public long timeoyt();
- String
- public String aa() default “12”;
- Class
- public Class cc() default java.util.Date.class
- Annotation(注解类型)
- public Annotation(自定义的注解类型) dd();
- (枚举类型)
- 以上类型的一维数组
作用
- 配置作用,例如@WebServlet()
配置:开发的时候部分信息不希望写死在程序中,例如数据库的用户名和密码,可以将用户名和密码存放在txt,properties,xml文件中,利用程序来读取文件的内容 - 编译检查
- 生成帮助文档
框架:一大堆工具类的集合,目的:加速项目开发
后期的学习中,框架部分hibernate,spring,struts2很多信息需要配置,提供了2种形式配置(xml,注解)
什么时候用注解来做配置呢?
如果配置信息不会发生修改的,例如servlet路径,建议使用注解的形式
如果配置信息需要频繁的修改,例如数据库的用户名和密码信息,建议使用传统方法(txt,properties,xml)
xml在属性多而复杂的情况下使用,properties主要用于写键值对
注解的作用时间范围
- @Retention(RetentionPolicy.CLASS)作用域在编译期间
- @Retention(RetentionPolicy.SOURCE)作用域在源代码期间
- @Retention(RetentionPolicy.RUNTIME)作用域在源代码期间
自定义注解的作用对象(目标)
- @Target(ElementType.METHOD)//对象是方法
- @Target(ElementType.ANNOTATION_TYPE)
- @Target(ElementType.CONSTRUCTOR)
- @Target(ElementType.PACKAGE)
- @Target(ElementType.TYPE)
class文件加载到内存
- Class clazz = Class.forName(“com.ytl.UserDao”);
- Class clazz01 = UserDao.class;
- Class clazz02 = new UserDao().getClass();
案例自定义Junit注解
- 自定义注解@MyTest
- 通过元注解@Retention@Target声明当前注解作用域以及目标对象,如果没有声明,在运行期间是无法获取到注解的信息的
- 定义UserDao
- 创建4个方法addUser,delUser,uptUser,getUser,在前三个方法上加载注释
- 定义类MyJunit,模拟Junit
- 将UserDao.class文件加载到内存
- 获取到字节码文件上的所有方法
- 遍历方法,判断每一个方法上是否加载了@MyTest注解
- 如果当前方法上设置了@MyTest,执行当前方法
源码
@MyTest代码
package com.ytl;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义注解,相当于JUnit@Test
//定义注解时,需要通过元注解Retention()来说明当前自定义注解的作用域(Class,Source,Runtime)
@Retention(RetentionPolicy.RUNTIME)//作用域在运行期间
//定义注解时,需要通过元注解Target()来说明当前自定义注解的目标对象(变量,方法,类)
@Target(ElementType.METHOD)
public @interface MyTest {
//在myTest注解中定义成员属性,默认值为-1
public long timeout() default -1;
}
UserDao源码
package com.ytl;
public class UserDao {
static {
System.out.println("加载静态代码块!");
}
@MyTest
public void addUser() {
System.out.println("增加用户");
}
@MyTest
public void delUser() {
System.out.println("删除用户");
}
@MyTest
public void uptUser() {
System.out.println("更新用户");
}
public void getUser() {
System.out.println("获取用户");
}
}
测试代码,MyJunit代码
package com.ytl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyJunit {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//加载UserDao.class字节码文件中的所有的方法,判断哪些方法上有自定义的注解@MyTest,
//如果有@MyTest,就执行方法,没有就不执行
//1.将UserDao.class字节码文件加载到内存中,class对象(代表字节码文件在内存里的对象)
Class clazz = Class.forName("com.ytl.UserDao");
// Class clazz01 = UserDao.class;
// Class clazz02 = new UserDao().getClass();
//2.获取字节码对象上的所有的方法,返回Method数组对象,数组中的每一个元素都代表Method对象(相当于字节码上的每一个方法)
Method[] mds = clazz.getMethods();
//3.变力字节码对象上的所有方法
for (Method method : mds) {
//测试方法的名称
//System.out.println(method.getName());
//判断当前方法上是否有注解@MyTest
//System.out.println(method.isAnnotationPresent(MyTest.class));
//如果有
if(method.isAnnotationPresent(MyTest.class)) {
method.invoke(new UserDao());
}
//如果没有注解,便忽略
}
}
}