Java

Java(L3)-- Junit、反射、注解

2019-12-15  本文已影响0人  刘点石

Junit、反射、注解

今天学习的是 Java 基础加强部分的内容,包括 Junit、反射、注解三部分内容。

Part I. Junit

  1. 测试的分类:

    • 黑盒测试:只关注输入与输出的结果,不关注内部实现的细节。
    • 白盒测试:既关注输入与输出的结果,又关注程序的执行流程。
  2. Junit:白盒测试

    步骤:

    • 定义一个测试类:
      • 类名一般为 XxxxTest,如 CalculatorTest
      • 报名一般为 xxx.xxx.test,如
    • 定义测试方法
      • 方法名:testXxxx,如 testAdd()
      • 返回值:void
      • 参数列表:空参
    • 给测试方法加注解 @Test
    • 导入 junit 依赖包

    运行结果:

    • 红色:测试方法运行发现错误

    • 绿色:测试方法运行未发现错误

    • 注:一般情况下,会用断言操作来处理测试函数中得到的结果

      Assert.assertEquals(期望的结果,运算的结果);
      

    补充:

    • @Before:修饰的方法会在测试方法前自动执行
    • @After:修饰的方法会在测试方法执行后自动执行

Part II. 反射

  1. Java代码执行的三个阶段

    一般情况下,Java 代码执行过程分为三个阶段:

    • Source 源代码阶段
    • Class 类对象阶段
    • Runtime 运行时阶段

    下面对这三个阶段依次解释:

    Source 阶段

    一般而言,当我们定义一个类时,会定义其成员变量构造方法成员方法,并将其放在一个 .java 文件中。该文件经过编译后会生成一个 .class 文件,即字节码文件,其中也包含了成员变量、构造方法和成员方法三部分。Source 源代码阶段主要包含这两个部分。

    Class 阶段:

    字节码文件经过类加载器(ClassLoader)加载到内存中,每个类经过加载后对应一个 Class 对象,该对象包括一个存放成员变量对象(field)的数组 Field [] fields;一个存放构造方法对象(constructor)的数组 Constructor [] constructors;和一个用于存放成员方法对象(method)的数组 Method [] methods。

    Runtime 阶段:

    内存中的 Class 类对象可以直接创建类对象,即进入 Runtime 阶段。

  2. 反射

    反射即程序在运行时可以访问、检测和修改它本身状态或行为的一种能力(维基百科)。在 Java 中,由 Source 阶段和 Runtime 阶段得到 Class 类对象并进行各类操作的过程称之为反射(我的理解)。

    得到 Class 对象的方法:

    • Class.forName("全类名"):将字节码加载进内存,返回 Class 对象

      多用于配置文件,将类名、方法名等定义在配置文件中。

    • 类名.class:通过类名的属性class获取

    • 对象.getClass():由对象获取 Class,getClass()方法在Object类中定义。

    注:同一个字节码文件 (*.class) 在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

  3. Class 对象的功能

  1. 案例

    要求:实现一个简易框架,可以从配置文件读取类名和方法名并执行该类的该方法。

    public static void main(String[] args) throws Exception {
        //读取配置文件并加载
        Properties pro = new Properties();
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
        pro.load(resourceAsStream);
     //获取类名和方法名
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
     //创建 Class 对象并创建实例
        Class<?> cls = Class.forName(className);
        Object o = cls.newInstance();
     //由方法名获取成员方法并执行
        Method method = cls.getMethod(methodName);
        method.invoke(o);
    }
    

Part III. 注解

注解(Annotation),也叫元数据,一种代码级别的说明。它是 JDK1.5 及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

  1. 注解的作用分类

    • 编写文档:通过代码里标识的注解生成文档
    • 代码分析:通过代码里标识的注解对代码进行分析
    • 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查(如 Override )
  2. JDK 中预定义的一些注解

    • @Override:检测被该注解标注的方法是否是继承自父类(接口)的
    • @Deprecated:该注解标注的内容,表示已过时
    • @SuppressWarnings:压制警告。若传递的是 “all” 参数,则压制所有警告
  3. 自定义注解

    • 格式:
    元注解
    public @interface 注解名称{
     属性列表;
    }
    
    • 本质:注解本质上就是一个接口,该接口默认继承Annotation接口
    public interface MyAnno extends java.lang.annotation.Annotation {}
    
    • 属性:

      由于注解本身是一个对象,它的“属性”实际上就是他的抽象函数。

      属性的返回值类型有下列取值:

      • 基本数据类型
      • String
      • 枚举
      • 注解
      • 以上类型的数组

      定义了属性,在使用时需要给属性赋值:

      • 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
      • 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
      • 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
    • 元注解:用于描述注解的注解

      • @Target:描述注解能够作用的位置

        其参数 ElementType 的取值:

        • TYPE:可以作用于类上
        • METHOD:可以作用于方法上
        • FIELD:可以作用于成员变量上
      • @Retention:描述注解被保留的阶段

        其参数一般取 RetentionPolicy.RUNTIME,会保留到字节码中并且会被 JVM 获取到

      • @Documented:描述注解是否被抽取到 api 文档中

      • @Inherited:描述注解是否被子类继承

    • 在程序中获取注解的属性值

      • 获取注解所修饰的对象(Class,Method 或 Field)

      • 使用 getAnnotation(Class) 获取制定的注解

        注:执行该方法实际上就是在内存中实现了该注解的子类对象

      • 使用注解的抽象函数获取属性值

    • 案例1:

      使用注解实现 Part II 中的简易框架:

      首先定义注解对象:

      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.TYPE)
      public @interface Pro {
          public abstract String className();
          public abstract String methodName();
      }
      

然后定义主类:

 ```java
 @Pro(className = "cn.dianshi.domain.Person", methodName = "sleep")
 public class ReflectTest {
     public static void main(String[] args) throws Exception {
         Class<ReflectTest> reflectTestClass = ReflectTest.class;
         Pro annotation = reflectTestClass.getAnnotation(Pro.class);
         String s = annotation.className();
         String s1 = annotation.methodName();
         System.out.println(s);
         System.out.println(s1);
 
         Class<?> aClass = Class.forName(s);
         Method method = aClass.getMethod(s1);
         Object o = aClass.newInstance();
         method.invoke(o);
     }
 }
 ```
上一篇 下一篇

猜你喜欢

热点阅读