今日内容 1. Junit单元测试
2. 反射
3. 注解 
Junit单元测试: 测试分类: 
Junit使用:白盒测试
步骤: 
定义一个测试类(测试用例,建议命名) 
 
测试类名:被测试的类名+Test    e.g.    CalculatorTest 
包名:xxx.xxx.xx.test        cn.itcast.test 
 
定义测试方法:可以独立运行(建议) 
 
方法名:test测试的方法名        testAdd()   
返回值:void 
参数列表:空参 
 
给方法加@Test 
导入junit依赖环境 
 
判定结果:
红色:失败 
绿色:成功 
一般我们会使用断言操作来处理结果
Assert.assertEquals(期望的结果,运算的结果); 
 
 
 
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package  cn.itcast.test;import  cn.itcast.junit.Calculator;import  org.junit.After;import  org.junit.Assert;import  org.junit.Before;import  org.junit.Test;public  class  CalculatorTest   {         @Before      public  void  init ()  {         System.out.println("init..." );     }          @After      public  void  close ()  {         System.out.println("close..." );     }          @Test      public  void  testAdd ()  {                          System.out.println("testAdd..." );         Calculator c  = new  Calculator();                  int  result = c.add(1 , 2 );                           Assert.assertEquals(3 ,result);     }     @Test      public  void  testSub ()  {                  Calculator c  = new  Calculator();         int  result = c.sub(1 , 2 );         System.out.println("testSub...." );         Assert.assertEquals(-1 ,result);     } } 
 
反射:框架设计的灵魂 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
反射:将类的各个组成部分封装为其他对象,这就是反射机制
好处:
可以在程序运行过程中,操作这些对象。(e.g.  IDEA软件中的自动提示,因为是在运行中) 
可以解耦,提高程序的可扩展性。 
 
获取Class对象的方式: 
Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象
多用于配置文件 ,将类名定义在配置文件中 。读取文件,加载类 
 
 
类名.class:通过类名的属性class获取
 
对象.getClass():getClass()方法在Object类中定义着。
 
 
结论:   *同一个字节码文件( .class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。** 
 
demo in class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package  cn.itcast.reflect;import  cn.itcast.domain.Person;import  cn.itcast.domain.Student;public  class  ReflectDemo1   {         public  static  void  main (String[] args)  throws  Exception  {                  Class cls1 = Class.forName("cn.itcast.domain.Person" );         System.out.println(cls1);                  Class cls2 = Person.class;         System.out.println(cls2);                  Person p = new  Person();         Class cls3 = p.getClass();         System.out.println(cls3);                  System.out.println(cls1 == cls2);         System.out.println(cls1 == cls3);         Class c = Student.class;         System.out.println(c == cls1);     } } 
 
Class对象功能(13个方法): 
获取功能:
获取成员变量们
Field[] getFields() :获取所有public修饰 的成员变量
 
Field getField(String name)   获取指定名称的 public修饰的成员变量
 
Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
 
Field getDeclaredField(String name)  
 
 
 
获取构造方法们
Constructor<?>[] getConstructors()  
 
Constructor<\T> getConstructor(类<?>… parameterTypes)  
 
Constructor<\T> getDeclaredConstructor(类<?>… parameterTypes)  
 
Constructor<?>[] getDeclaredConstructors()  
 
 
 
获取成员方法们:
Method[] getMethods()  
 
Method getMethod(String name, 类<?>… parameterTypes)  
 
Method[] getDeclaredMethods()  
 
Method getDeclaredMethod(String name, 类<?>… parameterTypes)  
 
 
 
获取全类名    
 
 
 
 
Field:成员变量(获取成员变量后做什么) 
设置值
void set(Object obj, Object value)   
 
 
获取值
 
忽略访问权限修饰符的安全检查(获取私有的成员变量的时候)
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 package  cn.itcast.reflect;import  cn.itcast.domain.Person;import  java.lang.reflect.Field;public  class  ReflectDemo2   {         public  static  void  main (String[] args)  throws  Exception  {                  Class personClass = Person.class;                           Field[] fields = personClass.getFields();         for  (Field field : fields) {             System.out.println(field);         }         System.out.println("------------" );                  Field a = personClass.getField("a" );                  Person p = new  Person();         Object value = a.get(p);         System.out.println(value);                  a.set(p,"张三" );         System.out.println(p);         System.out.println("===================" );                  Field[] declaredFields = personClass.getDeclaredFields();         for  (Field declaredField : declaredFields) {             System.out.println(declaredField);         }                  Field d = personClass.getDeclaredField("d" );                  d.setAccessible(true );         Object value2 = d.get(p);         System.out.println(value2);     } } 
 
Constructor:构造方法 
创建对象:
T newInstance(Object… initargs)   
 
 
如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package  cn.itcast.reflect;import  cn.itcast.domain.Person;import  java.lang.reflect.Constructor;import  java.lang.reflect.Field;public  class  ReflectDemo3   {         public  static  void  main (String[] args)  throws  Exception  {                  Class personClass = Person.class;                           Constructor constructor = personClass.getConstructor(String.class, int .class);         System.out.println(constructor);                  Object person = constructor.newInstance("张三" , 23 );         System.out.println(person);         System.out.println("----------" );         Constructor constructor1 = personClass.getConstructor();         System.out.println(constructor1);                  Object person1 = constructor1.newInstance();         System.out.println(person1);         Object o = personClass.newInstance();         System.out.println(o);              } } 
 
Method:方法对象 
执行方法(invoke):
Object invoke (Object obj, Object… args)   
 
 
获取方法名称:
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 package  cn.itcast.reflect;import  cn.itcast.domain.Person;import  java.lang.reflect.Constructor;import  java.lang.reflect.Method;public  class  ReflectDemo4   {         public  static  void  main (String[] args)  throws  Exception  {                  Class personClass = Person.class;                           Method eat_method = personClass.getMethod("eat" );         Person p = new  Person();                  eat_method.invoke(p);         Method eat_method2 = personClass.getMethod("eat" , String.class);                  eat_method2.invoke(p,"饭" );         System.out.println("-----------------" );                  Method[] methods = personClass.getMethods();         for  (Method method : methods) {             System.out.println(method);             String name = method.getName();             System.out.println(name);                      }                  String className = personClass.getName();         System.out.println(className);     } } 
 
案例(非常重要) 需求:写一个”框架”,不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
实现:
配置文件 
反射 
 
 
步骤:
将需要创建的对象的全类名和需要执行的方法定义在配置文件中 (创建properties对象) 
在程序中加载读取配置文件 
使用反射技术来加载类文件进内存 
创建对象 
执行方法 
 
 
 
如果对properties存储内存的知识很陌生的话,请去p380复习
Properties
1 2 className =cn.itcast.domain.Student methodName =sleep 
 
reflect_test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package  cn.itcast.reflect;import  cn.itcast.domain.Person;import  cn.itcast.domain.Student;import  java.io.IOException;import  java.io.InputStream;import  java.lang.reflect.Method;import  java.util.Properties;public  class  ReflectTest   {    public  static  void  main (String[] args)  throws  Exception  {                                                    Properties pro = new  Properties();                           ClassLoader classLoader = ReflectTest.class.getClassLoader();         InputStream is = classLoader.getResourceAsStream("pro.properties" );         pro.load(is);                  String className = pro.getProperty("className" );         String methodName = pro.getProperty("methodName" );                  Class cls = Class.forName(className);                  Object obj = cls.newInstance();                  Method method = cls.getMethod(methodName);                  method.invoke(obj);     } } 
 
注解: 
概念:说明程序的。给计算机看的
 
注释:用文字描述程序的。给程序员看的
 
定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
 
概念描述:
JDK1.5之后的新特性 
说明程序的 
使用注解:@注解名称 
 
 
作用分类:   ①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】   ②代码分析:通过代码里标识的注解对代码进行分析【使用反射】   ③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
 
 
JDK中预定义的一些注解 @Override    :检测被该注解标注的方法是否是继承自父类(接口)的
@Deprecated:该注解标注的内容,表示已过时
@SuppressWarnings:压制警告
一般传递参数all  @SuppressWarnings(“all”) 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package  cn.itcast.annotation;import  java.util.Date;@SuppressWarnings("all") public  class  AnnoDemo2   {    @Override      public  String toString ()   {         return  super .toString();     }     @Deprecated      public  void  show1 ()  {              }     public  void  show2 ()  {              }     public  void  demo ()  {         show1();         Date date = new  Date();     } } 
 
自定义注解 
MyAnoo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package  cn.itcast.annotation;public  @interface  MyAnno {     int  value ()  ;     Person per ()  ;     MyAnno2 anno2 ()  ;     String[] strs();             } 
 
Worker使用
1 2 3 4 5 6 7 8 9 10 11 12 13 package  cn.itcast.annotation;@MyAnno(value=12,per = Person.P1,anno2 = @MyAnno2,strs="bbb") @MyAnno3 public  class  Worker   {    @MyAnno3      public  String name = "aaa" ;     @MyAnno3      public  void  show ()  {     } } 
 
元注解:用于描述注解的注解 (target, retention之类的) 
@Target:描述注解能够作用的位置
ElementType取值:
TYPE:可以作用于类上 
METHOD:可以作用于方法上 
FIELD:可以作用于成员变量上 
 
 
 
 
@Retention:描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到 
 
 
@Documented:描述注解是否被抽取到api文档中 
@Inherited:描述注解是否被子类继承 
 
demo in class 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package  cn.itcast.annotation;import  java.lang.annotation.*;@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public  @interface  MyAnno3 {} 
 
在程序使用(解析)注解:获取注解中定义的属性值
获取注解定义的位置的对象  (Class,Method,Field) 
获取指定的注解 
调用注解中的抽象方法获取配置的属性值1 2 3 4 5 6 7 8 9 10 11 getAnnotation(Class)                   public  class  ProImpl  implements  Pro  {               public  String className ()  {                   return  "cn.itcast.annotation.Demo1" ;               }               public  String methodName ()  {                   return  "show" ;               }           } 
 
 
 
 
 
demo in class 
案例:简单的测试框架(pro.annotation) 
小结:
以后大多数时候,我们会使用注解,而不是自定义注解 
注解给谁用?
编译器 
给解析程序用 
 
 
注解不是程序的一部分,可以理解为注解就是一个标签 
 
 
 
注解大部分是用来替换配置文件的
步骤流程
 解析注解 
获取上边的注解对象 
调用注解对象定义的抽象方法,获取返回值 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 package  cn.itcast.annotation;import  java.io.InputStream;import  java.lang.reflect.Method;import  java.util.Properties;@Pro(className = "cn.itcast.annotation.Demo1",methodName = "show") public  class  ReflectTest   {    public  static  void  main (String[] args)  throws  Exception  {                                    Class<ReflectTest> reflectTestClass = ReflectTest.class;                          Pro an = reflectTestClass.getAnnotation(Pro.class);                           String className = an.className();         String methodName = an.methodName();         System.out.println(className);         System.out.println(methodName);                  Class cls = Class.forName(className);                  Object obj = cls.newInstance();                  Method method = cls.getMethod(methodName);                  method.invoke(obj);     } } 
 
pro.annotation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package  cn.itcast.annotation;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  Pro {    String className ()  ;     String methodName ()  ; }          
 
 
案例 Calculator类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package  cn.itcast.annotation.demo;public  class  Calculator   {         @Check      public  void  add ()  {         String str = null ;         str.toString();         System.out.println("1 + 0 ="  + (1  + 0 ));     }          @Check      public  void  sub ()  {         System.out.println("1 - 0 ="  + (1  - 0 ));     }          @Check      public  void  mul ()  {         System.out.println("1 * 0 ="  + (1  * 0 ));     }          @Check      public  void  div ()  {         System.out.println("1 / 0 ="  + (1  / 0 ));     }     public  void  show ()  {         System.out.println("永无bug..." );     } } 
 
check 注解
1 2 3 4 5 6 7 8 9 10 11 12 package  cn.itcast.annotation.demo;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  Check {} 
 
TestCheck类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 package  cn.itcast.annotation.demo;import  java.io.BufferedWriter;import  java.io.FileWriter;import  java.io.IOException;import  java.lang.reflect.InvocationTargetException;import  java.lang.reflect.Method;public  class  TestCheck   {    public  static  void  main (String[] args)  throws  IOException  {                  Calculator c = new  Calculator();                  Class cls = c.getClass();                  Method[] methods = cls.getMethods();         int  number = 0 ;         BufferedWriter bw = new  BufferedWriter(new  FileWriter("bug.txt" ));         for  (Method method : methods) {                          if (method.isAnnotationPresent(Check.class)){                                  try  {                     method.invoke(c);                 } catch  (Exception e) {                                                               number ++;                     bw.write(method.getName()+ " 方法出异常了" );                     bw.newLine();                     bw.write("异常的名称:"  + e.getCause().getClass().getSimpleName());                     bw.newLine();                     bw.write("异常的原因:" +e.getCause().getMessage());                     bw.newLine();                     bw.write("--------------------------" );                     bw.newLine();                 }             }         }         bw.write("本次测试一共出现 " +number+" 次异常" );         bw.flush();         bw.close();     } }