day01 注解与反射
# 今日内容
1.Junit单元测试
2.反射
3.注解
## Junit单元测试
测试分类
1.黑盒测试: 不需要写代码 给输入值 看程序是否能够输出期望的值
2.白盒测试:需要写代码 关注程序具体执行过程
使用步骤:
1.定义一个测试类(测试用例)
建议 类名:被测试的类名+Test
建议 包名:xxx.xxx.xx.test
2.定义测试方法:可以独立运行
建议:方法名 test+测试的方法名
建议返回值:使用void 无返回
建议:参数列表 建议空参
3.给方法加一个@Test
4.导入依赖
判定结果:红色 失败 绿色 成功
一般会使用断言来测试结果: Assert.assertEquals(17,calculator.add(8,9));
补充:@Before:修饰的方法会在测试方法之前被执行
@After:修饰的方法会在测试方法之后执行
##反射 框架设计的灵魂
*框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
*反射概念:将类的各个组成部分封装为其他对象 这就是反射机制

好处:
1.可以在程序运行中 操作这些对象
2.可以解耦 提高程序的可扩展性
*获取Class对象的方式:
1.Class.forName(“全类名”):将字节码文件加载到内存中,返回Class对象
*多用于配置文件 将类名定义在配置中
2.类名.class:通过类名.class属性获取
*多用于参数的传递
3 .对象.getClass(): Object中的方法
*多用于对象的获取字节码的方式
*结论:
同一个字节码文件(*.class)在一次程序运行过程中 只会被加载一次
不论用什么方法获取的Class对象都是同一个
*class对象功能:
*获取功能:
1.获取成员变量们
*Field[] getFields() 获取public的
*Field[] getField(String name)
*Field[] getDeclaredFields() //获取所有成员变量包括private
*Field[] getDeclaredField(String name)
2.获取构造方法
getConstructor(类<?>... parameterTypes)
getConstructors()
getDeclaredConstructors()
getDeclaredConstructor(类<?>... parameterTypes)
3.获取成员方法们
getMethod(String name, 类<?>... parameterTypes)
getMethods()
getDeclaredMethod(String name, 类<?>... parameterTypes)
getDeclaredMethods()
4.获取类名
getName()
*Field:成员变量
*操作:
1.设置值
void set(Object obj,Obiect value);
2.获取值
*get(Object obj)
3.忽略访问权限修饰符的安全检查
* age.setAccessible(true);//暴力反射
*Constructor:构造方法
*创建对象:
newInstance(Object...initargs)
*如果使用空参构造方法创建对象 可以简化 使用Class字节码对象调用newInstance方法
*Method:方法对象
*执行方法:
*Object invoke(Object obj,Object...args)
*获取方法名称
*String getName
#反射案例 :
*需求 :写一个“框架”,可以帮我们创建任意类的对象,并且执行其中任意方法
*实现:
1.配置文件
2.反射
*步骤:
1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2.在程序加载 读取配置文件
3.使用反射技术来加载类文件进内存
4.创建对象
5.执行方法
反射案例:
1 package cn.itcast.domain; 2 3 public class Student { 4 public void sleep(){ 5 System .out.println("睡觉"); } 6 7 }
配置文件

1 public static void main(String[] args) throws Exception { 2 // 创建Properties对象 3 Properties pro=new Properties(); 4 //加载配置文件 转换为一个集合 5 //获取class目录下的配置文件 6 ClassLoader classLoader = ReflectTest.class.getClassLoader(); 7 InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties"); 8 pro.load(resourceAsStream); 9 10 //获取配置文件中定义的类名 方法 11 String classname=pro.getProperty("className"); 12 String mName=pro.getProperty("methodName"); 13 14 //加载该类进内存 15 Class cls=Class.forName(classname); 16 //创建对象 17 Object o = cls.newInstance(); 18 //获取方法 19 Method method = cls.getMethod(mName); 20 //执行方法 21 method.invoke(o); 22 }
## 注解:
*概念:说明程序的 给计算机看的
*注释:用文字描述程序的,给程序员看的
定义: 注解(Annotation),也叫元数据。一种代码级别的说明,它是jdk1.5版本后引入的一个特性
与类,接口,枚举是在同一个层次,它可以声明再包,类,字段,方法,局部变量,方法参数等的前面
用来都这些元素进行说明,注释。
*概念描述: 1.JDk1.5指挥的新特性 2.说明程序的 3.使用注解:@注解名称
*作用分类:
1.编写文档:通过代码里标识的注解生成文档[生成文档doc文档]
2.代码分析:通过代码里标识的注解对代码进行分析【使用反射】
3.编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查
*JDK中预定义的一些注解
* @Override:检测被该注解标注的方法是否是继承自父类(接口)的
@Override public String toString() { return super.toString(); }
*@Deprecated:该注解标注的内容,表示已过时
@Deprecated public void show1(){ //有缺陷 } public void show2(){ //替代show1方法 } public void demo(){ show1(); //这里会提示你show不推荐使用 }
*@SuppressWarnings:压制警告 一般传递一个参数("all")
1 @SuppressWarnings("all") 2 public void show2(){ 3 //替代show1方法 4 }
*自定义注解
*格式:
元注解
public @interface 注解名称{ }
public @interface MyAnno { //属性:成员方法 int show2(); String name(); }
*本质:注解本质上就是一个接口,该接口默认继承Annotation接口
*public interface MyAnno extends java.lang.annotation.Annotation{ }
*属性:接口中的抽象方法
*要求:
1.属性的返回值类型 有下列取值 其他都不行
*基本数据类型
*String
*枚举
*注解
*以上类型的数组
2.定义了属性,再使用时需要给属性赋值
1.如果定义属性时:使用default关键字给属性默认初始值 则使用注解时可以不用赋值
2.如果只有一个属性需要赋值 并且属性的名称是value 则可以省略属性名
3.数组赋值时,则使用{ }包裹。如果数组中只有一个值 大括号可以省略
@MyAnno(show2 = 5,name = "我去") public void show2(){ }
*元注解:用于描述注解的注解
*@Target:描述注解能够作用的位置
@Target(value = ElementType.TYPE) //表示该注解只能作用于类上 public @interface MyAnno3 { //METHOD:可以作用于方法上 FIELD:作用于成员变量上 }
*@Retention:描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME)//当前被描述的注解,会被保留到class字节码文件中 并被jvm读取到 public @interface MyAnno3 { }
*@Documented:描述注解是否被抽取到api文档中
*@Inherited:描述注解是否被子类继承
@Inherited public @interface MyAnno3 { }
*在程序中使用(解析)注解
1.获取注解定义的位置的对象(class method Field)
2.获取指定的注解
* getAnnotation(Class)
3.调用注解中的抽象方法获取配置的属性值
/* * 自定义Pro注解描述需要执行的类名和方法名 * 1*/ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Pro { String className(); String methodName(); }
/* * 测试注解 * */ @Pro(className = "cn.itcast.annotation.demo1",methodName = "show") public class ReflectTest { /* * 不能更改该类的代码 * */ public static void main(String[] args) throws Exception { //1.解析注解 //2.获取该类的字节码文件对象 Class reflectTestClass=ReflectTest.class; //3.获取上边的注释对象 Pro an = (Pro) reflectTestClass.getAnnotation(Pro.class);//在内存中去生成了一个该注解接口的子类实现对象 String s = an.className(); String s1 = an.methodName(); //加载该类进内存 Class cls=Class.forName(s); //创建对象 Object o = cls.newInstance(); //获取方法 Method method = cls.getMethod(s1); //执行方法 method.invoke(o); } }
* 小结
1.以后大多数时候,我们会使用注解 而不是自定义注解
2.注解给谁用?
1.编译器
2.给解析程序使用
3.注解不是程序的一部分,可以理解为注解就是一个标签
注解案例:
1 @Target(ElementType.METHOD) 2 @Retention(RetentionPolicy.RUNTIME) 3 public @interface Check { 4 }
1 * 2 * 计算机类 3 * */ 4 public class Calculator { 5 /* 6 * 加法 7 * */ 8 @Check 9 public int add(int a,int b){ 10 return a/b; 11 } 12 /* 13 * 减法 14 * */ 15 public int sub(int a,int b){ 16 return a-b; 17 } 18 }
1 /* 2 * 简单的测试框架 3 * 当主方法执行后 会自动自行被检测的所有方法(加了Check的方法)判断方法是否有异常 记录到文件中 4 * */ 5 public class TestCheck { 6 public static void main(String[] args) throws IOException { 7 //创建计算机对象 8 Calculator calculator=new Calculator(); 9 //获取字节码对象 10 Class cls=calculator.getClass(); 11 //获取所有方法 12 Method[] methods = cls.getMethods(); 13 14 int num=0;//出现异常的次数 15 BufferedWriter bw=new BufferedWriter(new FileWriter("bug.txt")); 16 //判断方法是否有Check 17 for (Method method : methods) { 18 if (method.isAnnotationPresent(Check.class)){ 19 //有check注解就执行 20 try { 21 //执行方法 22 method.invoke(calculator,5,0); 23 } catch (Exception e) { 24 //捕获异常 25 //记录到文件中 26 num++; 27 bw.write(method.getName()+"方法出现异常"); 28 bw.newLine(); 29 bw.write("异常的名称是"+e.getCause().getClass().getSimpleName()); 30 bw.newLine(); 31 bw.write("异常的原因是:"+e.getCause().getMessage()); 32 bw.newLine(); 33 bw.write("-----------------"); 34 } 35 } 36 } 37 bw.write("本次测试一共出现"+num+"次异常"); 38 bw.flush(); 39 bw.close(); 40 } 41 }
注解解析图:


浙公网安备 33010602011771号